diff --git a/.travis.yml b/.travis.yml index 44b6c4df0..27d41af30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,15 @@ branches: except: - /^v[0-9]/ -os: -- linux -- osx language: cpp -compiler: -- gcc -- clang +matrix: + include: + - os: linux + compiler: gcc + - os: osx + compiler: clang sudo: false diff --git a/appveyor.yml b/appveyor.yml index d3ad27ed3..e29c4e96f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,7 +43,7 @@ before_build: (Get-Content source\base\build.h).replace('//{POV_AUTOBUILD_2}', $env:pov_autobuild_2) | Set-Content source\base\build.h (Get-Content source\base\build.h).replace('//{POV_AUTOBUILD_3}', $env:pov_autobuild_3) | Set-Content source\base\build.h (Get-Content source\base\build.h).replace('YOUR NAME (YOUR EMAIL)', $env:pov_authorized_by) | Set-Content source\base\build.h - (Get-Content source\base\build.h).replace('#error Please fill in BUILT_BY, then remove this line', '') | Set-Content source\base\build.h + (Get-Content source\base\build.h).replace('#error "Please fill in BUILT_BY, then remove this line"', '') | Set-Content source\base\build.h build: project: windows/vs10/povray.sln diff --git a/changes.txt b/changes.txt index e637a21ea..ccdaa787d 100644 --- a/changes.txt +++ b/changes.txt @@ -49,6 +49,22 @@ Prior to the release of 3.7.1, the following items still need urgent attention: New Features ------------ +- A new finish parameter, `use_alpha`, has been added to suppress highlights + and reflections depending on pigment transparency. + +- Array elements no longer have to be of the same type. + +- Support for variable-size arrays has been added. + +- A new data container, `dictionary`, has been added to support structured + storage of data. + +- Pseudo-dictionaries `local` and `global` have been added, allowing to + specifically access local or global identifiers, respectively. + +- A new special pigment pattern, `user_defined`, has been added to define the + pigment colour directly in terms of a set of functions. + - A new pattern, `potential`, has been added to define a pattern based on the potential field of a blob or isosurface object. @@ -86,9 +102,6 @@ New Features assignments. The main purpose is to allow macros to return a set of values rather than just a single one. -- `local()` and `global()` pseudo-functions have been added to specifically - refer to a local or global identifier, respectively. - - The macro syntax has been extended to allow for optional parameters. - Light sources' distance-based fading can now be set to obey an inverse-power @@ -196,8 +209,18 @@ Fixed or Mitigated Issues Reported by Static Code Analysis Coverity Scan defects targeted deliberately: +- CID 967251: 'Constant' variable guards dead code +- CID 967254: 'Constant' variable guards dead code +- CID 967261: Logically dead code +- CID 967262: Logically dead code +- CID 967273: Explicit null dereferenced +- CID 967296: Parse Warning +- CID 967297: Parse Warning - CID 967377: Uninitialized pointer field - CID 967400: Uninitialized pointer field +- CID 967410: Structurally dead code +- CID 967412: Structurally dead code +- CID 1129008: Division or modulo by zero - CID 1129016: Uninitialized pointer read - CID 1129017: Uninitialized scalar variable - CID 1372548: Non-virtual destructor @@ -205,7 +228,16 @@ Coverity Scan defects targeted deliberately: - CID 1372555: Operands don't affect result - CID 1372556: Wrong operator used - CID 1372557: Wrong operator used +- CID 1372558: Resource leak in object +- CID 1372560: Logically dead code - CID 1372562: Non-array delete for scalars +- CID 1372566: Unchecked dynamic_cast +- CID 1372567: Unchecked dynamic_cast +- CID 1372603: Resource leak +- CID 1372604: Dereference before null check +- CID 1372605: Dereference before null check +- CID 1372606: Dereference before null check +- CID 1372607: Dereference before null check - CID 1372608: Sizeof not portable - CID 1372626: Uninitialized scalar variable - CID 1372636: Uninitialized pointer field @@ -224,6 +256,12 @@ Coverity Scan defects targeted deliberately: - CID 1372655: Structurally dead code - CID 1372656: Structurally dead code - CID 1372657: Unused value +- CID 1373648: Out-of-bounds access +- CID 1373649: Free of address-of expression +- CID 1373651: Logically dead code +- CID 1373652: Dereference before null check +- CID 1373653: Write to pointer after free +- CID 1373654: Use after free Coverity Scan defects eliminated in passing: @@ -342,6 +380,8 @@ Reported via GitHub: - #49 ("Latest version from Git won't build with MS Visual Studio 2015") - #50 ("Make error in Ubuntu 14.04") - #53 ("Standard include files may mess up the language version") +- #129 ("Port of FS331 - Intersection causes quadric to disappear") +- #153 ("vector list trailing comma error sor lathe sphere_sweep") Reported via FlySpray: @@ -354,9 +394,15 @@ Reported via FlySpray: - FS#316 ("inverse keyword does not work properly with fractals") - FS#317 ("problem with +D option at specific output file dimensions") - FS#318 ("method 3 (default) scattering media is too bright & causes artifacts when nested") +- FS#331 ("Intersection causes quadric to disappear") +- FS#336 ("#fopen w/o OPEN_TYPE crash povray (segfault)") Reported via the Newsgroups: +- <3c4bb31d$1@news.povray.org> + (2002-01-21, povray.beta-test, "<1, 0, 0> + 1*t") + Inconsistency in automatic scalar-to-vector promotion. + - <53ea2dae@news.povray.org> (2014-08-12, povray.binaries.images, "unexplained") Precision issue led to `<1,1,1>.grey` not evaluating to 1 on sone systems. @@ -414,6 +460,10 @@ Reported via the Newsgroups: (2016-08-17, povray.binaries.scene-files, "Wrong normal direction on triangle{ }s") Bug in flat trianges that could cause interior_texture to show on the wrong side. +- <58090935$1@news.povray.org> + (2016-10-20, povray.programming, "Re: solving polynomials") + Misplaced `break` in polynomial solving code. + Reported via Windows Crash Reports: - crash report #???, dump file #988 diff --git a/platform/unix/syspovtimer.cpp b/platform/unix/syspovtimer.cpp index f688cb5d2..e86fc853a 100644 --- a/platform/unix/syspovtimer.cpp +++ b/platform/unix/syspovtimer.cpp @@ -80,7 +80,7 @@ void Delay(unsigned int msec) POV_ASSERT(msec < 1000); // On some systems, usleep() does not support sleeping for 1 second or more. usleep (msec * (useconds_t)1000); #else -#error Bad compile-time configuration. +#error "Bad compile-time configuration." #endif } diff --git a/source-doc/compiler.md b/source-doc/compiler.md index 9800c92a6..bfd4caad3 100644 --- a/source-doc/compiler.md +++ b/source-doc/compiler.md @@ -6,7 +6,7 @@ General Presumptions While POV-Ray is being developed with portability high in mind, the C++ standard allows for some degrees of freedom that we consider too exotic to cater to. We therefore presume all compilers and runtime environments to adhere to the -following additional restrictions: +following restrictions: - **Char Size**: The `char` data type is currently presumed to be exactly 8 bits wide. @@ -19,7 +19,11 @@ following additional restrictions: separator, in include directives. - **Integer Division**: Integer division is presumed to round towards zero. This also implies that the remainder (as - computed by the modulus operator `%`) is negative (or zero) if the dividend and divisor have different sign. + computed by the modulus operator `%`) is negative (or zero) if the dividend and divisor have different signs. + +Failure to meet the above restrictions will cause in undefined behaviour. + +Further restrictions may apply, but shall prompt a compile-time error if not satisfied. POVMS Additional Restrictions diff --git a/source-doc/styleguide.md b/source-doc/styleguide.md index 0b2353938..76c749f72 100644 --- a/source-doc/styleguide.md +++ b/source-doc/styleguide.md @@ -223,6 +223,10 @@ Miscellaneous Coding Rules - **Locale**: Do not tamper with the C locale (i.e. do not call `setlocale` or any other function doing the same job), as plenty of code in POV-Ray relies on it remaining set to the default. + - **Optimization**: Do not over-optimize your code. While we do want POV-Ray to be fast, we also want it to be + reasonably maintainable, and modern compilers generally do a good enough job at automatic optimization that you can + focus on keeping your code robust and easy to understand. + Code Documentation ================== diff --git a/source/base/build.h b/source/base/build.h index f9f07322d..c7dc4aeff 100644 --- a/source/base/build.h +++ b/source/base/build.h @@ -55,7 +55,7 @@ /// Specifies the person or organization responsible for this build. /// @attention Please set this to your real name, and/or include a working email or website address to contact you. #define BUILT_BY "YOUR NAME (YOUR EMAIL)" -#error Please fill in BUILT_BY, then remove this line +#error "Please fill in BUILT_BY, then remove this line" #endif #endif // POVRAY_BASE_BUILD_H diff --git a/source/base/colour.cpp b/source/base/colour.cpp index 305e83bd8..02a6ddfc3 100644 --- a/source/base/colour.cpp +++ b/source/base/colour.cpp @@ -54,7 +54,7 @@ namespace pov_base #else - #error TODO! + #error "TODO!" #endif diff --git a/source/base/colour.h b/source/base/colour.h index 77a7ed1b4..e03b6a976 100644 --- a/source/base/colour.h +++ b/source/base/colour.h @@ -578,7 +578,7 @@ class GenericRGBColour mColour[BLUE] = col.mColour[2]; } #else - #error TODO! + #error "TODO!" #endif }; @@ -1736,7 +1736,7 @@ class GenericColour mColour[2] = col.blue(); } #else - #error TODO! + #error "TODO!" #endif }; diff --git a/source/base/image/gif.cpp b/source/base/image/gif.cpp index 9edd857ef..ccd859164 100644 --- a/source/base/image/gif.cpp +++ b/source/base/image/gif.cpp @@ -125,8 +125,7 @@ Image *Read (IStream *file, const Image::ReadOptions& options, bool IsPOTFile) { case EOF: throw POV_EXCEPTION(kFileDataErr, "Unexpected EOF reading GIF file"); - finished = true; - break ; + break; case ';': /* End of the GIF dataset. */ finished = true; diff --git a/source/base/image/image.cpp b/source/base/image/image.cpp index 2139631c9..9f2063590 100644 --- a/source/base/image/image.cpp +++ b/source/base/image/image.cpp @@ -3254,6 +3254,7 @@ class FileBackedPixelContainer throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file read failed."); m_CurrentBlock = block; } + POV_IMAGE_ASSERT (m_Blocksize != 0); memcpy(&pixel, m_Buffer[(y * (POV_LONG)(m_Width) + x) % m_Blocksize], sizeof(pixel)); } #if 0 diff --git a/source/base/mathutil.h b/source/base/mathutil.h index 299a6dcd5..4d6dc7b7b 100644 --- a/source/base/mathutil.h +++ b/source/base/mathutil.h @@ -120,12 +120,12 @@ inline T wrap(T val, T upperLimit) // wrap signed integer value into the range [0..upperLimit); // (this is equivalent to the modulus operator for positive values, but not for negative ones) -template -inline T wrapInt(T val, T upperLimit) +template +inline T2 wrapInt(T1 val, T2 upperLimit) { - T tempVal = val % upperLimit; + T1 tempVal = val % upperLimit; - if (tempVal < T(0)) + if (tempVal < T1(0)) { // For negative values, the modulus operator may return a value in the range [1-upperLimit..-1]; // transpose such results into the range [1..upperLimit-1]. @@ -135,7 +135,25 @@ inline T wrapInt(T val, T upperLimit) // sanity check; this should never kick in, unless wrapInt() has an implementation error. POV_MATHUTIL_ASSERT((tempVal >= 0) && (tempVal < upperLimit)); - return tempVal; + return (T2)tempVal; +} + +// wrap signed integer value into the range [0..upperLimit); +// (this is equivalent to the modulus assignment operator for positive values, but not for negative ones) +template +inline void setWrapInt(T1 val, T2 upperLimit) +{ + val %= upperLimit; + + if (val < T1(0)) + { + // For negative values, the modulus operator may return a value in the range [1-upperLimit..-1]; + // transpose such results into the range [1..upperLimit-1]. + val += upperLimit; + } + + // sanity check; this should never kick in, unless wrapInt() has an implementation error. + POV_MATHUTIL_ASSERT((val >= 0) && (val < upperLimit)); } // round up/down to a multiple of some value diff --git a/source/base/path.cpp b/source/base/path.cpp index 57d151f24..ebded80c0 100644 --- a/source/base/path.cpp +++ b/source/base/path.cpp @@ -262,7 +262,7 @@ void Path::ParsePathString(const UCS2String& p) // Such an implementation should reside in `platform/foo/syspovpath.cpp`. #ifdef POV_PATH_SEPARATOR_2 -#error The portable implementation of ParsePathString does not support alternative path separator characters. +#error "The portable implementation of ParsePathString does not support alternative path separator characters." #endif bool Path::ParsePathString (UCS2String& volume, vector& dirnames, UCS2String& filename, const UCS2String& path) diff --git a/source/base/textstreambuffer.cpp b/source/base/textstreambuffer.cpp index fe090cb98..5f72b388e 100644 --- a/source/base/textstreambuffer.cpp +++ b/source/base/textstreambuffer.cpp @@ -185,7 +185,7 @@ void TextStreamBuffer::printfile(FILE *file, POV_LONG lines) if((stopposset == true) && (stoppos == ((POV_LONG)(ftell(file)) - 1))) // only if walking backwards stop at initial position break; - // count newlines in file and replace newlines with system specific newline charcater + // count newlines in file and replace newlines with system specific newline character if((chr == 10) || (chr == 13)) { chr = fgetc(file); diff --git a/source/base/types.h b/source/base/types.h index 98bf038c3..933026553 100644 --- a/source/base/types.h +++ b/source/base/types.h @@ -271,27 +271,6 @@ struct POVRect unsigned int GetHeight() const { return (bottom - top + 1); } }; -class GenericSetting -{ - public: - explicit GenericSetting(bool set = false): set(set) {} - void Unset() { set = false; } - bool isSet() const { return set; } - protected: - bool set; -}; - -class FloatSetting : public GenericSetting -{ - public: - explicit FloatSetting(double data = 0.0, bool set = false): data(data), GenericSetting(set) {} - double operator=(double b) { data = b; set = true; return data; } - operator double() const { return data; } - double operator()(double def) const { if (set) return data; else return def; } - private: - double data; -}; - enum StringEncoding { kStringEncoding_ASCII = 0, diff --git a/source/base/version.h b/source/base/version.h index c330c1670..8ca3b5571 100644 --- a/source/base/version.h +++ b/source/base/version.h @@ -45,7 +45,7 @@ #define OFFICIAL_VERSION_STRING "3.7.1" #define OFFICIAL_VERSION_NUMBER 371 -#define POV_RAY_PRERELEASE "alpha.8826150" +#define POV_RAY_PRERELEASE "alpha.8889454" #if (POV_RAY_IS_AUTOBUILD == 1) && ((POV_RAY_IS_OFFICIAL == 1) || (POV_RAY_IS_SEMI_OFFICIAL == 1)) #ifdef POV_RAY_PRERELEASE diff --git a/source/core/bounding/boundingbox.cpp b/source/core/bounding/boundingbox.cpp index a7bc0298e..fdb5c98ac 100644 --- a/source/core/bounding/boundingbox.cpp +++ b/source/core/bounding/boundingbox.cpp @@ -896,7 +896,7 @@ bool sort_and_split(BBOX_TREE **Root, BBOX_TREE **&Finite, size_t *numOfFiniteOb // For debugging only. // TODO MESSAGE Debug_Info("Reallocing Finite to %d\n", maxfinitecount); Finite = reinterpret_cast(POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes")); - delete[] areaCache; + delete[] *areaCache; *areaCache = new BBoxScalar[maxfinitecount]; } diff --git a/source/core/colour/spectral.h b/source/core/colour/spectral.h index 78e53d8f5..3d3ee7170 100644 --- a/source/core/colour/spectral.h +++ b/source/core/colour/spectral.h @@ -97,7 +97,7 @@ class SpectralBand #if (NUM_COLOUR_CHANNELS == 3) return (GetHueIntegral(wavelength+bandwidth/2) - GetHueIntegral(wavelength-bandwidth/2)) * (SPECTRAL_BANDWIDTH/bandwidth); #else - #error TODO! + #error "TODO!" #endif } diff --git a/source/core/configcore.h b/source/core/configcore.h index 006778522..86f793697 100644 --- a/source/core/configcore.h +++ b/source/core/configcore.h @@ -165,22 +165,22 @@ namespace pov #define POV_BLEND_MAP_DEBUG POV_DEBUG #endif -/// @def POV_SHAPE_DEBUG -/// Enable run-time sanity checks for geometric shapes. +/// @def POV_PATTERN_DEBUG +/// Enable run-time sanity checks for pattern handling. /// /// Define as non-zero integer to enable, or zero to disable. /// -#ifndef POV_SHAPE_DEBUG - #define POV_SHAPE_DEBUG POV_DEBUG +#ifndef POV_PATTERN_DEBUG + #define POV_PATTERN_DEBUG POV_DEBUG #endif -/// @def POV_PATTERN_DEBUG -/// Enable run-time sanity checks for pattern handling. +/// @def POV_PIGMENT_DEBUG +/// Enable run-time sanity checks for pigment handling. /// /// Define as non-zero integer to enable, or zero to disable. /// -#ifndef POV_PATTERN_DEBUG - #define POV_PATTERN_DEBUG POV_DEBUG +#ifndef POV_PIGMENT_DEBUG + #define POV_PIGMENT_DEBUG POV_DEBUG #endif /// @def POV_RADIOSITY_DEBUG @@ -210,6 +210,15 @@ namespace pov #define POV_REFPOOL_DEBUG POV_DEBUG #endif +/// @def POV_SHAPE_DEBUG +/// Enable run-time sanity checks for geometric shapes. +/// +/// Define as non-zero integer to enable, or zero to disable. +/// +#ifndef POV_SHAPE_DEBUG + #define POV_SHAPE_DEBUG POV_DEBUG +#endif + /// @def POV_SUBSURFACE_DEBUG /// Enable run-time sanity checks for subsurface light transport. /// @@ -236,18 +245,18 @@ namespace pov #define POV_BLEND_MAP_ASSERT(expr) POV_ASSERT_DISABLE(expr) #endif -#if POV_SHAPE_DEBUG - #define POV_SHAPE_ASSERT(expr) POV_ASSERT_HARD(expr) -#else - #define POV_SHAPE_ASSERT(expr) POV_ASSERT_DISABLE(expr) -#endif - #if POV_PATTERN_DEBUG #define POV_PATTERN_ASSERT(expr) POV_ASSERT_HARD(expr) #else #define POV_PATTERN_ASSERT(expr) POV_ASSERT_DISABLE(expr) #endif +#if POV_PIGMENT_DEBUG + #define POV_PIGMENT_ASSERT(expr) POV_ASSERT_HARD(expr) +#else + #define POV_PIGMENT_ASSERT(expr) POV_ASSERT_DISABLE(expr) +#endif + #if POV_RADIOSITY_DEBUG #define POV_RADIOSITY_ASSERT(expr) POV_ASSERT_HARD(expr) #else @@ -266,6 +275,12 @@ namespace pov #define POV_REFPOOL_ASSERT(expr) POV_ASSERT_DISABLE(expr) #endif +#if POV_SHAPE_DEBUG + #define POV_SHAPE_ASSERT(expr) POV_ASSERT_HARD(expr) +#else + #define POV_SHAPE_ASSERT(expr) POV_ASSERT_DISABLE(expr) +#endif + #if POV_SUBSURFACE_DEBUG #define POV_SUBSURFACE_ASSERT(expr) POV_ASSERT_HARD(expr) #else diff --git a/source/core/lighting/photons.cpp b/source/core/lighting/photons.cpp index ba7174136..79badc961 100644 --- a/source/core/lighting/photons.cpp +++ b/source/core/lighting/photons.cpp @@ -298,10 +298,10 @@ void PhotonTrace::ComputeLightedTexture(MathColour& LightCol, ColourChannel&, co // Get distance based attenuation. interior = isect.Object->interior.get(); - AttCol = MathColour(interior->Old_Refract); if (interior != NULL) { + AttCol = MathColour(interior->Old_Refract); if (ray.IsInterior(interior) == true) { if ((interior->Fade_Power > 0.0) && (fabs(interior->Fade_Distance) > EPSILON)) @@ -318,8 +318,8 @@ void PhotonTrace::ComputeLightedTexture(MathColour& LightCol, ColourChannel&, co } } } + LightCol *= AttCol; } - LightCol *= AttCol; // set size here threadData->photonDepth += isect.Depth; diff --git a/source/core/lighting/radiosity.cpp b/source/core/lighting/radiosity.cpp index a7819896b..e5705e673 100644 --- a/source/core/lighting/radiosity.cpp +++ b/source/core/lighting/radiosity.cpp @@ -919,7 +919,6 @@ bool RadiosityCache::Load(const Path& inputFile) double nearest; int goodreads = 0; int count; - bool goodparse = true; DBL brightness; char normal_string[30], to_nearest_string[30]; char line[101]; @@ -927,7 +926,7 @@ bool RadiosityCache::Load(const Path& inputFile) //info->Gather_Total.clear(); //info->Gather_Total_Count = 0; - while (!(got_eof = !fd->getline (line, 99)) && goodparse) + while (!(got_eof = !fd->getline (line, 99))) { switch ( line[0] ) { @@ -958,7 +957,7 @@ bool RadiosityCache::Load(const Path& inputFile) ); illuminance = ToMathColour(tempCol); #else - #error TODO! + #error "TODO!" #endif if ( count == 11 ) { @@ -993,19 +992,11 @@ bool RadiosityCache::Load(const Path& inputFile) } // end switch } // end while-reading loop - if ( !got_eof || !goodparse ) - { - ;// TODO MESSAGE PossibleError("Cannot process radiosity cache file at line %d.", (int)line_num); - ok = false; - } + if ( goodreads > 0 ) + ;// TODO MESSAGE Debug_Info("Reloaded %d values from radiosity cache file.\n", goodreads); else - { - if ( goodreads > 0 ) - ;// TODO MESSAGE Debug_Info("Reloaded %d values from radiosity cache file.\n", goodreads); - else - ;// TODO MESSAGE PossibleError("Unable to read any values from the radiosity cache file."); - ok = true; - } + ;// TODO MESSAGE PossibleError("Unable to read any values from the radiosity cache file."); + ok = true; ReleaseBlockPool(pool); diff --git a/source/core/material/normal.cpp b/source/core/material/normal.cpp index 048ad2c64..90a5b3a51 100644 --- a/source/core/material/normal.cpp +++ b/source/core/material/normal.cpp @@ -838,7 +838,7 @@ void Perturb_Normal(Vector3d& Layer_Normal, const TNORMAL *Tnormal, const Vector /* No normal_map. */ - if (Tnormal->Type <= LAST_NORM_ONLY_PATTERN) + if (Tnormal->Type <= LAST_SPECIAL_NORM_PATTERN) { Warp_Normal(Layer_Normal,Layer_Normal, Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG)); @@ -886,7 +886,6 @@ void Perturb_Normal(Vector3d& Layer_Normal, const TNORMAL *Tnormal, const Vector UnWarp_Normal(Layer_Normal,Layer_Normal,Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG)); - } if ( Intersection ) @@ -983,7 +982,7 @@ static DBL Hermite_Cubic(DBL T1, const Vector2d& UV1, const Vector2d& UV2) * DESCRIPTION * * CHANGES -* Added intersectin parameter for UV mapping - NK 1998 +* Added intersection parameter for UV mapping - NK 1998 * ******************************************************************************/ diff --git a/source/core/material/pattern.cpp b/source/core/material/pattern.cpp index 31d04f6fa..c020f4f67 100644 --- a/source/core/material/pattern.cpp +++ b/source/core/material/pattern.cpp @@ -281,6 +281,42 @@ ColourBlendMapConstPtr BasicPattern::GetDefaultBlendMap() const { return gpDefau bool BasicPattern::HasSpecialTurbulenceHandling() const { return false; } +ImagePatternImpl::ImagePatternImpl() : + pImage(NULL) +{} + +ImagePatternImpl::ImagePatternImpl(const ImagePatternImpl& obj) : + pImage(obj.pImage ? Copy_Image(obj.pImage) : NULL) +{} + +ImagePatternImpl::~ImagePatternImpl() +{ + if (pImage) + Destroy_Image(pImage); +} + + +ColourPattern::ColourPattern() : + BasicPattern() +{} + +ColourPattern::ColourPattern(const ColourPattern& obj) : + BasicPattern(obj) +{} + +DBL ColourPattern::Evaluate(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const +{ + TransColour colour; + if (Evaluate(colour, EPoint, pIsection, pRay, pThread)) + return colour.Greyscale(); + else + return 0.0; +} + +unsigned int ColourPattern::NumDiscreteBlendMapEntries() const { return 0; } +bool ColourPattern::CanMap() const { return false; } + + ContinuousPattern::ContinuousPattern() : BasicPattern(), waveType(kWaveType_Ramp), @@ -338,10 +374,17 @@ DBL ContinuousPattern::Evaluate(const Vector3d& EPoint, const Intersection *pIse } unsigned int ContinuousPattern::NumDiscreteBlendMapEntries() const { return 0; } +bool ContinuousPattern::CanMap() const { return true; } +bool DiscretePattern::CanMap() const { return false; } unsigned int PlainPattern::NumDiscreteBlendMapEntries() const { return 1; } +unsigned int AveragePattern::NumDiscreteBlendMapEntries() const { return 0; } +bool AveragePattern::CanMap() const { return true; } +DBL AveragePattern::Evaluate(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const { return 0.0; } +bool AveragePattern::HasSpecialTurbulenceHandling() const { return false; } + ColourBlendMapConstPtr AgatePattern::GetDefaultBlendMap() const { return gpDefaultBlendMap_Agate; } @@ -357,6 +400,94 @@ ColourBlendMapConstPtr CubicPattern::GetDefaultBlendMap() const { return gpDefau unsigned int CubicPattern::NumDiscreteBlendMapEntries() const { return 6; } +ColourFunctionPattern::ColourFunctionPattern() +{ + for (int iChannel = 0; iChannel < 5; ++iChannel) + { + pFn[iChannel] = NULL; + } +} + +ColourFunctionPattern::ColourFunctionPattern(const ColourFunctionPattern& obj) : + ColourPattern(obj) +{ + for (int iChannel = 0; iChannel < 5; ++iChannel) + { + if (obj.pFn[iChannel]) + pFn[iChannel] = obj.pFn[iChannel]->Clone(); + else + pFn[iChannel] = NULL; + } +} + +ColourFunctionPattern::~ColourFunctionPattern() +{ + for (int iChannel = 0; iChannel < 5; ++iChannel) + { + if (pFn[iChannel]) + delete pFn[iChannel]; + } +} + +bool ColourFunctionPattern::Evaluate(TransColour& result, const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const +{ + for (int iChannel = 0; iChannel < 5; ++iChannel) + { + ColourChannel channelValue = 0.0; + if (pFn[iChannel]) + { + GenericFunctionContextPtr pCtx = pFn[iChannel]->AcquireContext(pThread); + pFn[iChannel]->InitArguments(pCtx); + for (int iDimension = 0; iDimension < 3; ++iDimension) + pFn[iChannel]->PushArgument(pCtx, EPoint[iDimension]); + channelValue = pFn[iChannel]->Execute(pCtx); + pFn[iChannel]->ReleaseContext(pCtx); + } + switch (iChannel) + { + case 3: result.filter() = channelValue; break; + case 4: result.transm() = channelValue; break; + default: result.colour()[iChannel] = channelValue; break; + } + } + return true; +} + +bool ColourFunctionPattern::HasTransparency() const +{ + return (pFn[3] || pFn[4]); +} + + +bool ColourImagePattern::Evaluate(TransColour& result, const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const +{ + // TODO ALPHA - the caller does expect non-premultiplied data, but maybe he could profit from premultiplied data? + + int reg_number; + DBL xcoor = 0.0, ycoor = 0.0; + + // If outside map coverage area, return clear + + if (map_pos(EPoint, this, &xcoor, &ycoor)) + { + result = ToTransColour(RGBFTColour(1.0, 1.0, 1.0, 0.0, 1.0)); + return false; + } + else + { + RGBFTColour rgbft; + image_colour_at(pImage, xcoor, ycoor, rgbft, ®_number, false); + result = ToTransColour(rgbft); + return true; + } +} + +bool ColourImagePattern::HasTransparency() const +{ + return (!pImage || pImage->Once_Flag || !is_image_opaque(pImage)); +} + + DensityFilePattern::DensityFilePattern() : densityFile(NULL) {} @@ -402,24 +533,6 @@ ColourBlendMapConstPtr HexagonPattern::GetDefaultBlendMap() const { return gpDef unsigned int HexagonPattern::NumDiscreteBlendMapEntries() const { return 3; } -ImagePattern::ImagePattern() : - pImage(NULL) -{} - -ImagePattern::ImagePattern(const ImagePattern& obj) : - ContinuousPattern(obj), - pImage(NULL) -{ - if (obj.pImage) - pImage = Copy_Image(obj.pImage); -} - -ImagePattern::~ImagePattern() -{ - if (pImage) - Destroy_Image(pImage); -} - DBL ImagePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const { return image_pattern(EPoint, this); @@ -3303,8 +3416,8 @@ DBL PavementPattern::tetragonal (const Vector3d& EPoint) const case 6: case 8: case 9: - xv %= 6; if (xv < 0) { xv += 6; } - zv &= 0x01; + setWrapInt (xv, 6); + setWrapInt (zv, 2); lng = 6; break; case 4: @@ -3312,17 +3425,17 @@ DBL PavementPattern::tetragonal (const Vector3d& EPoint) const case 19: case 20: lng = 0; - zv %= 6; if (zv <0) { zv += 6; } + setWrapInt (zv, 6); xv += 5*zv; - xv %= 6; if (xv <0) { xv += 6; } + setWrapInt (xv, 6); break; case 11: case 18: case 27: lng = 0; - zv %= 6; if (zv <0) { zv += 6; } + setWrapInt (zv, 6); xv += zv; - xv %= 6; if (xv <0) { xv += 6; } + setWrapInt (xv, 6); break; case 10: case 12: @@ -3332,71 +3445,71 @@ DBL PavementPattern::tetragonal (const Vector3d& EPoint) const case 25: case 26: lng = 4; - xv &= 0x03; - zv %= 3; if (zv<0) { zv += 3; } + setWrapInt (xv, 4); + setWrapInt (zv, 3); break; case 13: case 32: lng = 3; - zv &= 0x03; - xv %= 3; if (xv < 0) { xv += 3; } + setWrapInt (zv, 4); + setWrapInt (xv, 3); break; case 14: lng = 3; - zv %= 6; if (zv < 0) { zv += 6; } + setWrapInt (zv, 6); xv += 2 * (zv/2); - zv &= 0x01; - xv %= 3; if (xv < 0) { xv += 3; } + setWrapInt (zv, 2); + setWrapInt (xv, 3); break; case 15: lng = 2; - xv %= 6; if (xv < 0) { xv+= 6; } + setWrapInt (xv, 6); zv += (xv/2); - xv &= 0x01; - zv %= 3; if (zv<0) { zv += 3; } + setWrapInt (xv, 2); + setWrapInt (zv, 3); break; case 16: case 17: lng = 6; - zv %= 12; if (zv <0) { zv += 12; } + setWrapInt (zv, 12); xv += zv/2; - zv &= 0x01; - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (zv, 2); + setWrapInt (xv, 6); break; case 23: case 28: lng = 6; - zv %= 12; if (zv <0) { zv += 12; } + setWrapInt (zv, 12); xv += 4* (zv/2); - zv &= 0x01; - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (zv, 2); + setWrapInt (xv, 6); break; case 29: case 30: lng = 6; - zv &= 0x03; + setWrapInt (zv, 4); xv += 3* (zv/2); - zv &= 0x01; - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (zv, 2); + setWrapInt (xv, 6); break; case 31: lng = 0; - zv %= 3; if (zv <0) { zv += 3; } + setWrapInt (zv, 3); xv += 4* zv; - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (xv, 6); break; case 33: lng = 0; - zv %= 12; if (zv < 0) { zv += 12; } + setWrapInt (zv, 12); xv += 7*zv; - xv %= 12; if (xv < 0) { xv += 12; } + setWrapInt (xv, 12); break; case 34: lng = 4; - zv %= 6; if (zv<0) { zv += 6;} + setWrapInt (zv, 6); xv += 2 * (zv/3); - xv &= 0x03; - zv %= 3; if (zv<0) { zv += 3;} + setWrapInt (xv, 4); + setWrapInt (zv, 3); break; } how = hexagon[Number-1][xv+zv*lng]; @@ -3406,69 +3519,69 @@ DBL PavementPattern::tetragonal (const Vector3d& EPoint) const { case 0: case 1: - xv %= 5; if (xv <0) { xv += 5; } - zv &= 0x01; + setWrapInt (xv, 5); + setWrapInt (zv, 2); break; case 2: case 9: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += 3 * (zv/2); - xv %= 5; if (xv <0) { xv += 5; } - zv &= 0x01; + setWrapInt (xv, 5); + setWrapInt (zv, 2); break; case 10: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += 4*(zv/2); - xv %= 5; if (xv <0) { xv += 5; } - zv &= 0x01; + setWrapInt (xv, 5); + setWrapInt (zv, 2); break; case 3: - zv %= 5; if (zv <0) { zv += 5; } + setWrapInt (zv, 5); xv += 2*zv; - xv %= 5; if (xv <0) { xv += 5; } - zv = 0x0; + setWrapInt (xv, 5); + zv = 0; break; case 4: - zv %= 5; if (zv <0) { zv += 5; } + setWrapInt (zv, 5); xv += 2 * zv; - xv %= 5; if (xv <0) { xv += 5; } - zv = 0x00; + setWrapInt (xv, 5); + zv = 0; break; case 5: case 6: case 8: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += zv; - xv %= 10; if (xv <0) { xv += 10; } - zv = 0x00; + setWrapInt (xv, 10); + zv = 0; break; case 11: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += 8* zv; - xv %= 10; if (xv <0) { xv += 10; } - zv = 0x00; + setWrapInt (xv, 10); + zv = 0; break; case 7: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += 3*zv; - xv %= 10; if (xv <0) { xv += 10; } - zv = 0x00; + setWrapInt (xv, 10); + zv = 0; break; } how = pentagon[Number-1][xv+zv*5]; break; case 4: - xv &= 0x03; - zv &= 0x03; + setWrapInt (xv, 4); + setWrapInt (zv, 4); how = tetragon[Number-1][xv+zv*4]; break; case 3: - xv %= 3; if (xv < 0) { xv += 3; } - zv &= 0x01; + setWrapInt (xv, 3); + setWrapInt (zv, 2); how = trigon[Number-1][xv+zv*3]; break; case 2: - zv &= 0x01; + setWrapInt (zv, 2); how = digon[zv]; break; case 1: @@ -3874,41 +3987,41 @@ DBL PavementPattern::trigonal (const Vector3d& EPoint) const case 9: xv += 5*zv; zv = 0; - xv %= 6; if (xv <0) { xv += 6;} + setWrapInt (xv, 6); lng = 0; break; case 2: case 10: case 11: - zv &= 0x01; + setWrapInt (zv, 2); xv += 3*zv; - xv %= 6; if (xv <0) { xv += 6;} + setWrapInt (xv, 6); lng = 0; break; case 3: - xv += 14*((zv%6+((zv%6)<0?6:0))/2); - xv %= 6; if (xv <0) { xv += 6;} + xv += 14*(wrapInt (zv, 6)/2); + setWrapInt (xv, 6); lng = 6; - zv &= 0x01; + setWrapInt (zv, 2); break; case 4: case 8: - xv += 8*((zv%6+((zv%6)<0?6:0))/2); - xv %= 6; if (xv <0) { xv += 6;} + xv += 8*(wrapInt (zv, 6)/2); + setWrapInt (xv, 6); lng = 6; - zv &= 0x01; + setWrapInt (zv, 2); break; case 5: - xv %= 6; if (xv <0) { xv += 6;} + setWrapInt (xv, 6); lng = 6; - zv &= 0x01; + setWrapInt (zv, 2); break; case 6: case 7: - xv -= ((zv%12+((zv%12)<0?12:0))/3); - xv &= 3; + xv -= wrapInt (zv, 12)/3; + setWrapInt (xv, 4); lng = 4; - zv %= 3; if (zv <0) { zv +=3;} + setWrapInt (zv, 3); break; } how = trihexagon[Number-1][xv+zv*lng]; @@ -3919,32 +4032,32 @@ DBL PavementPattern::trigonal (const Vector3d& EPoint) const case 0: case 1: case 2: - zv &= 0x01; + setWrapInt (zv, 2); xv += 5*zv; - xv %= 10; if (xv <0) { xv += 10; } - zv = 0x00; + setWrapInt (xv, 10); + zv = 0; break; case 3: - zv %= 10; if (zv <0) { zv += 10; } + setWrapInt (zv, 10); xv += 3*zv; - xv %= 10; if (xv <0) { xv += 10; } - zv = 0x00; + setWrapInt (xv, 10); + zv = 0; break; } how = tripentagon[Number-1][xv]; break; case 4: - zv &= 0x03; + setWrapInt (zv, 4); xv += zv; - xv &= 0x03; - zv &= 0x01; + setWrapInt (xv, 4); + setWrapInt (zv, 2); how = tritetragon[Number-1][xv+zv*4]; break; case 3: - zv &= 0x01; + setWrapInt (zv, 2); xv += 3*zv; - xv %= 6; if (xv < 0) { xv += 6; } - zv = 0x00; + setWrapInt (xv, 6); + zv = 0; how = tritrigon[Number-1][xv]; break; case 2: @@ -4693,24 +4806,24 @@ DBL PavementPattern::hexagonal (const Vector3d& EPoint) const case 5: case 6: case 19: - zv %= 10; if (zv < 0) { zv += 10; } - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (zv, 10); + setWrapInt (xv, 6); xv += 6*zv; /* 60 */ zv = 0; break; case 1: case 4: case 9: - zv -= 2*(((xv%30+(xv%30<0?30:0))/6)); - zv %= 10; if (zv < 0) { zv += 10; } - xv %= 6; if (xv < 0) { xv += 6; } + zv -= 2*(wrapInt (xv, 30)/6); + setWrapInt (zv, 10); + setWrapInt (xv, 6); xv += 6*zv; /* 60 */ zv = 0; break; case 7: - zv -= 7*(((xv%60+(xv%60<0?60:0))/3)); - zv %= 20; if (zv < 0) { zv += 20; } - xv %= 3; if (xv < 0) { xv += 3; } + zv -= 7*(wrapInt (xv, 60)/3); + setWrapInt (zv, 20); + setWrapInt (xv, 3); xv += 3*zv; /* 60 */ zv = 0; break; @@ -4722,25 +4835,25 @@ DBL PavementPattern::hexagonal (const Vector3d& EPoint) const case 17: case 20: case 21: - zv += 2*(((xv%30+(xv%30<0?30:0))/6)); - zv %= 10; if (zv < 0) { zv += 10; } - xv %= 6; if (xv < 0) { xv += 6; } + zv += 2*(wrapInt (xv, 30)/6); + setWrapInt (zv, 10); + setWrapInt (xv, 6); xv += 6*zv; /* 60 */ zv = 0; break; case 11: case 16: - zv -= 6*(((xv%30+(xv%30<0?30:0))/6)); - zv %= 10; if (zv < 0) { zv += 10; } - xv %= 6; if (xv < 0) { xv += 6; } + zv -= 6*(wrapInt (xv, 30)/6); + setWrapInt (zv, 10); + setWrapInt (xv, 6); xv += 6*zv; /* 60 */ zv = 0; break; case 12: case 18: - zv += 6*(((xv%30+(xv%30<0?30:0))/6)); - zv %= 10; if (zv < 0) { zv += 10; } - xv %= 6; if (xv < 0) { xv += 6; } + zv += 6*(wrapInt (xv, 30)/6); + setWrapInt (zv, 10); + setWrapInt (xv, 6); xv += 6*zv; /* 60 */ zv = 0; break; @@ -4751,42 +4864,42 @@ DBL PavementPattern::hexagonal (const Vector3d& EPoint) const switch(Number-1) { case 0: - zv &= 0x07; - xv %= 6; if(xv <0) { xv += 6; } + setWrapInt (zv, 8); + setWrapInt (xv, 6); xv += 6*zv; /* 48 */ zv = 0; break; case 3: - zv -= 2*(((xv%24+(xv%24<0?24:0))/6)); - zv %= 8; if (zv < 0) { zv += 8; } - xv %= 6; if (xv < 0) { xv += 6; } + zv -= 2*(wrapInt (xv, 24)/6); + setWrapInt (zv, 8); + setWrapInt (xv, 6); xv += 6*zv; /* 48 */ zv = 0; break; case 2: - zv &= 0x01; - xv %= 12; if (xv < 0) { xv += 12; } + setWrapInt (zv, 2); + setWrapInt (xv, 12); xv += 12*zv; /* 24 */ zv = 0; break; case 5: case 4: - zv -= 2*(((xv%24+(xv%24<0?24:0))/6)); - zv %= 8; if (zv < 0) { zv += 8; } - xv %= 6; if (xv < 0) { xv += 6; } + zv -= 2*(wrapInt (xv, 24)/6); + setWrapInt (zv, 8); + setWrapInt (xv, 6); xv += 6*zv; /* 48 */ zv = 0; break; case 1: - zv += 2*(((xv%12+(xv%12<0?12:0))/6)); - zv %= 8; if (zv < 0) { zv += 8; } - xv %= 6; if (xv < 0) { xv += 6; } + zv += 2*(wrapInt (xv, 12)/6); + setWrapInt (zv, 8); + setWrapInt (xv, 6); xv += 6*zv; /* 48 */ zv = 0; break; case 6: - zv %= 4; if (zv < 0) { zv += 4; } - xv %= 12; if (xv < 0) { xv += 12; } + setWrapInt (zv, 4); + setWrapInt (xv, 12); xv += 12*zv; /* 48 */ zv = 0; break; @@ -4797,37 +4910,37 @@ DBL PavementPattern::hexagonal (const Vector3d& EPoint) const switch(Number-1) { case 0: - zv %= 6; if(zv <0) { zv += 6; } - xv %= 6; if(xv <0) { xv += 6; } + setWrapInt (zv, 6); + setWrapInt (xv, 6); xv += 6*zv; zv = 0; break; case 1: - zv += 2*(((xv%18+(xv%18<0?18:0))/6)); - zv %= 6; if(zv <0) { zv += 6; } - xv %= 6; if(xv <0) { xv += 6; } + zv += 2*(wrapInt (xv, 18)/6); + setWrapInt (zv, 6); + setWrapInt (xv, 6); xv += 6*zv; zv = 0; break; case 2: - zv &= 0x01; - xv %= 18; if (xv < 0) { xv += 18; } + setWrapInt (zv, 2); + setWrapInt (xv, 18); xv += 18*zv; - zv = 0x00; + zv = 0; break; } how = hextrigon[Number-1][xv]; break; case 2: - zv &= 0x01; - xv %= 6; if (xv < 0) { xv += 6; } + setWrapInt (zv, 2); + setWrapInt (xv, 6); how = hexdigon[Number-1][xv+6*zv]; break; case 1: default: - zv &= 0x01; + setWrapInt (zv, 2); xv += 3*zv; - xv %= 6; if (xv <0) { xv += 6;} + setWrapInt (xv, 6); lng = 0; how = hexmonogon[Number-1][xv]; break; @@ -5983,7 +6096,7 @@ DBL DensityFilePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection * f222 = (DBL)Data->Density8[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)UNSIGNED8_MAX; } else - POV_ASSERT(false); + POV_PATTERN_ASSERT (false); density = ((f111 * xi + f112 * xx) * yi + (f121 * xi + f122 * xx) * yy) * (1.0 - zz) + ((f211 * xi + f212 * xx) * yi + (f221 * xi + f222 * xx) * yy) * zz; @@ -6638,7 +6751,7 @@ DBL TriangularPattern::Evaluate(const Vector3d& EPoint, const Intersection *pIse answer = 3.0; break; default: - POV_ASSERT(false); + POV_PATTERN_ASSERT (false); break; } } @@ -6701,7 +6814,7 @@ DBL JuliaPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsect mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -6769,7 +6882,7 @@ DBL Julia3Pattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsec mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -6837,7 +6950,7 @@ DBL Julia4Pattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsec mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -6906,7 +7019,7 @@ DBL JuliaXPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsec mindist2 = a*a+b*b; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); binomial_coeff = &(gaBinomialCoefficients[(fractalExponent+1)*fractalExponent/2]); @@ -7035,7 +7148,7 @@ DBL Magnet1MPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIs mindist2 = 10000; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7112,7 +7225,7 @@ DBL Magnet1JPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIs mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7195,7 +7308,7 @@ DBL Magnet2MPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIs c1c2i = (c1r+c2r)*y; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7277,7 +7390,7 @@ DBL Magnet2JPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIs c1c2i = (c1r+c2r)*ci; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7356,7 +7469,7 @@ DBL Mandel2Pattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7423,7 +7536,7 @@ DBL Mandel3Pattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7490,7 +7603,7 @@ DBL Mandel4Pattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse mindist2 = a2+b2; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); for (col = 0; col < it_max; col++) { @@ -7558,7 +7671,7 @@ DBL MandelXPattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse mindist2 = a*a+b*b; it_max = maxIterations; - POV_ASSERT(it_max > 0); + POV_PATTERN_ASSERT (it_max > 0); binomial_coeff = &(gaBinomialCoefficients[(fractalExponent+1)*fractalExponent/2]); @@ -8787,7 +8900,7 @@ DBL FractalPattern::ExteriorColour(int iters, DBL a, DBL b) const case 0: return exteriorFactor; case 1: - POV_ASSERT(maxIterations > 0); + POV_PATTERN_ASSERT (maxIterations > 0); return (DBL)iters / (DBL)maxIterations; case 2: return a * exteriorFactor; @@ -9006,6 +9119,8 @@ void Destroy_Density_File(DENSITY_FILE *Density_File) void Read_Density_File(IStream *file, DENSITY_FILE *df) { + POV_PATTERN_ASSERT (file); + size_t x, y, z, sx, sy, sz, len; if (df == NULL) @@ -9075,10 +9190,7 @@ void Read_Density_File(IStream *file, DENSITY_FILE *df) else throw POV_EXCEPTION_STRING("Invalid density file size"); - if (file != NULL) - { - delete file; - } + delete file; } } diff --git a/source/core/material/pattern.h b/source/core/material/pattern.h index 202ff5d5c..a86108fc1 100644 --- a/source/core/material/pattern.h +++ b/source/core/material/pattern.h @@ -55,9 +55,8 @@ namespace pov * Global preprocessor defines ******************************************************************************/ -#define LAST_SPECIAL_PATTERN BITMAP_PATTERN -#define LAST_NORM_ONLY_PATTERN GENERIC_NORM_ONLY_PATTERN -#define LAST_INTEGER_PATTERN GENERIC_INTEGER_PATTERN +#define LAST_SPECIAL_PATTERN COLOUR_PATTERN +#define LAST_SPECIAL_NORM_PATTERN GENERIC_SPECIAL_NORM_PATTERN /// Legacy Identifier IDs for the various patterns. /// @@ -70,9 +69,11 @@ enum PATTERN_IDS PLAIN_PATTERN, AVERAGE_PATTERN, UV_MAP_PATTERN, - BITMAP_PATTERN, + BITMAP_PATTERN, ///< image-based pattern (except `image_map`) + IMAGE_MAP_PATTERN, ///< `image_map` + COLOUR_PATTERN, - // The following former normal patterns require special handling. They must be kept seperate for now. + // The following former normal patterns require special handling. They must be kept separate for now. WAVES_PATTERN, RIPPLES_PATTERN, @@ -82,39 +83,9 @@ enum PATTERN_IDS FACETS_PATTERN, DENTS_PATTERN, - GENERIC_NORM_ONLY_PATTERN, ///< Pattern does not need any legacy special handling anywhere, except for its property of having a special implementation for normals. + GENERIC_SPECIAL_NORM_PATTERN, ///< Pattern does not need any legacy special handling anywhere, except for its property of having a special implementation for normals. - // The following patterns return integer values. They must be kept together in the list. Any new integer functions added must be added here. - - OBJECT_PATTERN, // NOT in all cases as the others in this group - BRICK_PATTERN, // NOT in all cases as the others in this group - - GENERIC_INTEGER_PATTERN, ///< Pattern does not need any legacy special handling anywhere, except for its property of returning an integer value. - - // The following patterns return float values. They must be kept together and seperate from those above. - - MARBLE_PATTERN, - WOOD_PATTERN, - AGATE_PATTERN, - JULIA_PATTERN, - JULIA3_PATTERN, - JULIA4_PATTERN, - JULIAX_PATTERN, - MANDEL_PATTERN, - MANDEL3_PATTERN, - MANDEL4_PATTERN, - MANDELX_PATTERN, - MAGNET1M_PATTERN, - MAGNET1J_PATTERN, - MAGNET2M_PATTERN, - MAGNET2J_PATTERN, - CRACKLE_PATTERN, - DENSITY_FILE_PATTERN, - IMAGE_PATTERN, - PAVEMENT_PATTERN, - TILING_PATTERN, - - GENERIC_PATTERN ///< Pattern does not need any legacy special handling anywhere + GENERIC_PATTERN ///< Pattern does not need any legacy special handling anywhere }; /* flags for patterned stuff */ @@ -161,7 +132,7 @@ const int kFractalMaxExponent = 33; //****************************************************************************** // Forward declarations to avoid pulling in entire header files. -// required by ImagePattern (defined in support/imageutil.h) +// required by ImagePatternImpl (defined in support/imageutil.h) class ImageData; //****************************************************************************** @@ -275,6 +246,12 @@ struct BasicPattern /// virtual bool HasSpecialTurbulenceHandling() const; + /// Whether the pattern can be used with maps. + /// + /// @return `true` if the pattern can be used with maps. + /// + virtual bool CanMap() const = 0; + protected: /// Helper method generating an independent copy of the specified object. @@ -293,6 +270,39 @@ struct BasicPattern static PatternPtr Clone(const T& obj) { return PatternPtr(new T(obj)); } }; +/// Generic abstract class providing additions to the basic pattern interface, as well as common code, for all patterns +/// returning colours. +/// +struct ColourPattern : public BasicPattern +{ + ColourPattern(); + ColourPattern(const ColourPattern& obj); + + virtual DBL Evaluate(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const; + virtual unsigned int NumDiscreteBlendMapEntries() const; + virtual bool CanMap() const; + + /// Evaluates the pattern at a given point in space. + /// + /// @note Derived classes should _not_ override this, but @ref EvaluateRaw() instead. + /// + /// @param[out] result The pattern's colour at the given point in space. + /// @param[in] EPoint The point of interest in 3D space. + /// @param[in] pIsection Additional information about the intersection. Evaluated by some patterns. + /// @param[in] pRay Additional information about the ray. Evaluated by some patterns. + /// @param[in,out] pThread Additional thread-local data. Evaluated by some patterns. Some patterns, such as the + /// crackle pattern, store cached data here. + /// @return `false` if the pattern is undefined at the given point in space. + /// + virtual bool Evaluate(TransColour& result, const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const = 0; + + /// Whether the pattern has transparency. + /// + /// @return `true` if the pattern has transparency. + /// + virtual bool HasTransparency() const = 0; +}; + /// Generic abstract class providing additions to the basic pattern interface, as well as common code, for all /// continuous pattern implementations. /// @@ -346,12 +356,14 @@ struct ContinuousPattern : public BasicPattern virtual DBL EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const = 0; virtual unsigned int NumDiscreteBlendMapEntries() const; + virtual bool CanMap() const; }; /// Generic abstract class providing additions to the basic pattern interface, as well as common code, for all /// discrete pattern implementations. struct DiscretePattern : public BasicPattern { + virtual bool CanMap() const; }; /// Implements a plain pattern with all-zero values for any point in space. @@ -363,6 +375,30 @@ struct PlainPattern : public DiscretePattern virtual bool HasSpecialTurbulenceHandling() const; }; +/// Implements a dummy pattern for `average` pseudo-pattern. +struct AveragePattern : public BasicPattern +{ + virtual PatternPtr Clone() const { return BasicPattern::Clone(*this); } + virtual DBL Evaluate(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const; + virtual unsigned int NumDiscreteBlendMapEntries() const; + virtual bool HasSpecialTurbulenceHandling() const; + virtual bool CanMap() const; +}; + +/// Class providing additional data members for image-based patterns. +/// +/// @todo The additional member variables should possibly be encapsulated. +/// +struct ImagePatternImpl +{ + ImageData *pImage; + + ImagePatternImpl(); + ImagePatternImpl(const ImagePatternImpl& obj); + virtual ~ImagePatternImpl(); +}; + + /// Implements the `agate` pattern. struct AgatePattern : public ContinuousPattern { @@ -419,6 +455,30 @@ struct CheckerPattern : public DiscretePattern virtual unsigned int NumDiscreteBlendMapEntries() const; }; +/// Implements the `user_defined` pattern. +/// +/// @todo The additional member variables should possibly be encapsulated. +/// +struct ColourFunctionPattern : public ColourPattern +{ + GenericScalarFunctionPtr pFn[5]; + + ColourFunctionPattern(); + ColourFunctionPattern(const ColourFunctionPattern& obj); + virtual ~ColourFunctionPattern(); + virtual PatternPtr Clone() const { return BasicPattern::Clone(*this); } + virtual bool Evaluate(TransColour& result, const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const; + virtual bool HasTransparency() const; +}; + +/// Implements the `image_map` pattern. +struct ColourImagePattern : public ColourPattern, public ImagePatternImpl +{ + virtual PatternPtr Clone() const { return BasicPattern::Clone(*this); } + virtual bool Evaluate(TransColour& result, const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const; + virtual bool HasTransparency() const; +}; + /// Implements the `crackle` pattern. struct CracklePattern : public ContinuousPattern { @@ -589,17 +649,9 @@ struct HexagonPattern : public DiscretePattern virtual unsigned int NumDiscreteBlendMapEntries() const; }; -/// Implements the `image_map` pattern. -/// -/// @todo The additional member variables should possibly be encapsulated. -/// -struct ImagePattern : public ContinuousPattern +/// Implements image-based mapped patterns. +struct ImagePattern : public ContinuousPattern, public ImagePatternImpl { - ImageData *pImage; - - ImagePattern(); - ImagePattern(const ImagePattern& obj); - virtual ~ImagePattern(); virtual PatternPtr Clone() const { return BasicPattern::Clone(*this); } virtual DBL EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const; }; diff --git a/source/core/material/pigment.cpp b/source/core/material/pigment.cpp index 7d01a37f1..7642f4145 100644 --- a/source/core/material/pigment.cpp +++ b/source/core/material/pigment.cpp @@ -270,7 +270,8 @@ void Post_Pigment(PIGMENT *Pigment, bool* pHasFilter) break; case PLAIN_PATTERN: - case BITMAP_PATTERN: + case IMAGE_MAP_PATTERN: + case COLOUR_PATTERN: break; @@ -296,7 +297,7 @@ void Post_Pigment(PIGMENT *Pigment, bool* pHasFilter) break; } - /* Now we test wether this pigment is opaque or not. [DB 8/94] */ + // Now we test whether this pigment is opaque or not. hasFilter = false; @@ -305,11 +306,9 @@ void Post_Pigment(PIGMENT *Pigment, bool* pHasFilter) hasFilter = true; } - if ((Pigment->Type == BITMAP_PATTERN) && - (dynamic_cast(Pigment->pattern.get())->pImage != NULL)) + if (dynamic_cast(Pigment->pattern.get())) { - // bitmaps are transparent if they are used only once, or the image is not opaque - if ((dynamic_cast(Pigment->pattern.get())->pImage->Once_Flag) || !is_image_opaque(dynamic_cast(Pigment->pattern.get())->pImage)) + if (dynamic_cast(Pigment->pattern.get())->HasTransparency()) hasFilter = true; } @@ -432,13 +431,15 @@ bool Compute_Pigment (TransColour& colour, const PIGMENT *Pigment, const Vector3 Colour_Found = Pigment->Blend_Map->ComputeUVMapped(colour, Intersect, ray, Thread); break; - case BITMAP_PATTERN: + case IMAGE_MAP_PATTERN: + case COLOUR_PATTERN: Warp_EPoint (TPoint, EPoint, Pigment); colour.Clear(); - Colour_Found = image_map (TPoint, Pigment, colour); + POV_ASSERT(dynamic_cast(Pigment->pattern.get())); + Colour_Found = dynamic_cast(Pigment->pattern.get())->Evaluate(colour, TPoint, Intersect, ray, Thread); break; diff --git a/source/core/material/texture.cpp b/source/core/material/texture.cpp index 883485f72..b906f21a3 100644 --- a/source/core/material/texture.cpp +++ b/source/core/material/texture.cpp @@ -1187,6 +1187,8 @@ FINISH *Create_Finish() New->SubsurfaceTranslucency.Clear(); New->SubsurfaceAnisotropy.Clear(); + New->AlphaKnockout = false; + return(New); } @@ -1582,9 +1584,9 @@ int Test_Opacity(const TEXTURE *Texture) /* Layer is not opaque if the image map is used just once. */ - if (dynamic_cast(Layer->pattern.get())->pImage != NULL) + if (dynamic_cast(Layer->pattern.get())->pImage) { - if (dynamic_cast(Layer->pattern.get())->pImage->Once_Flag) + if (dynamic_cast(Layer->pattern.get())->pImage->Once_Flag) { break; } diff --git a/source/core/material/texture.h b/source/core/material/texture.h index a930fb1f1..95aa00c31 100644 --- a/source/core/material/texture.h +++ b/source/core/material/texture.h @@ -112,7 +112,7 @@ struct Texture_Struct : public Pattern_Struct PIGMENT *Pigment; TNORMAL *Tnormal; FINISH *Finish; - vector Materials; // used for BITMAP_PATTERN (and only there) + vector Materials; // used for `material_map` (and only there) }; struct Finish_Struct @@ -132,6 +132,7 @@ struct Finish_Struct SNGL Reflect_Metallic; // MBP int Conserve_Energy; // added by NK Dec 19 1999 bool UseSubsurface; // whether to use subsurface light transport + bool AlphaKnockout; // whether pigment alpha knocks out finish effects }; diff --git a/source/core/math/chi2.cpp b/source/core/math/chi2.cpp index d20ef6a78..c91e7f685 100644 --- a/source/core/math/chi2.cpp +++ b/source/core/math/chi2.cpp @@ -289,12 +289,8 @@ DBL chdtri(DBL df, DBL y) DBL x; if ((y < 0.0) || (y > 1.0) || (df < 1.0)) - { throw POV_EXCEPTION_STRING("Illegal values in chdtri()."); - return (0.0); - } - x = igami(0.5 * df, y); return (2.0 * x); diff --git a/source/core/math/polynomialsolver.cpp b/source/core/math/polynomialsolver.cpp index fa4739e98..331c326e9 100644 --- a/source/core/math/polynomialsolver.cpp +++ b/source/core/math/polynomialsolver.cpp @@ -1705,9 +1705,9 @@ int Solve_Polynomial(int n, const DBL *c0, DBL *r, int sturm, DBL epsilon, Rende stats[Roots_Eliminated]++; roots = polysolve(n-1, c, r); - } - break; + break; + } } /* Solve n-th order polynomial. */ diff --git a/source/core/render/trace.cpp b/source/core/render/trace.cpp index 8b68c4d3b..f76460041 100644 --- a/source/core/render/trace.cpp +++ b/source/core/render/trace.cpp @@ -150,10 +150,8 @@ double Trace::TraceRay(Ray& ray, MathColour& colour, ColourChannel& transm, COLC // Check if we're busy shooting too many radiosity sample rays at an unimportant object if (ray.GetTicket().radiosityImportanceQueried >= 0.0) { - if (found) - { - ray.GetTicket().radiosityImportanceFound = bestisect.Object->RadiosityImportance(sceneData->radiositySettings.defaultImportance); - } + if (found && bestisect.Object->RadiosityImportanceSet) + ray.GetTicket().radiosityImportanceFound = bestisect.Object->RadiosityImportance; else ray.GetTicket().radiosityImportanceFound = sceneData->radiositySettings.defaultImportance; @@ -860,6 +858,9 @@ void Trace::ComputeLightedTexture(MathColour& resultColour, ColourChannel& resul else att = layCol.Opacity(); + if (layer->Finish->AlphaKnockout) + listWNRX->back().reflec *= att; + // now compute the BRDF or BSSRDF contribution tmpCol.Clear(); @@ -964,7 +965,12 @@ void Trace::ComputeLightedTexture(MathColour& resultColour, ColourChannel& resul // (We don't need to do this for (non-radiosity) rays during pretrace, as it does not affect radiosity sampling) if(!ray.IsPretraceRay()) { - if((layer->Finish->Diffuse != 0.0) || (layer->Finish->DiffuseBack != 0.0) || (layer->Finish->Specular != 0.0) || (layer->Finish->Phong != 0.0)) + if (((layer->Finish->Diffuse != 0.0) || + (layer->Finish->DiffuseBack != 0.0) || + (layer->Finish->Specular != 0.0) || + (layer->Finish->Phong != 0.0)) && + ((!layer->Finish->AlphaKnockout) || + (att != 0.0))) { MathColour classicContribution; @@ -1643,6 +1649,8 @@ void Trace::ComputeOneDiffuseLight(const LightSource &lightsource, const Vector3 // surface-only diffuse term, they should use layered textures. ComputeDiffuseColour(finish, lightsourceray.Direction, eye.Direction, layer_normal, tmpCol, lightcolour, layer_pigment_colour, relativeIor, attenuation, backside); + MathColour tempLightColour = (finish->AlphaKnockout ? lightcolour * attenuation : lightcolour); + // NK rad - don't compute highlights for radiosity gather rays, since this causes // problems with colors being far too bright // don't compute highlights for diffuse backside illumination @@ -1650,11 +1658,13 @@ void Trace::ComputeOneDiffuseLight(const LightSource &lightsource, const Vector3 { if(finish->Phong > 0.0) { - ComputePhongColour(finish, lightsourceray.Direction, eye.Direction, layer_normal, tmpCol, lightcolour, layer_pigment_colour, relativeIor); + ComputePhongColour (finish, lightsourceray.Direction, eye.Direction, layer_normal, tmpCol, + tempLightColour, layer_pigment_colour, relativeIor); } if(finish->Specular > 0.0) - ComputeSpecularColour(finish, lightsourceray.Direction, -eye.Direction, layer_normal, tmpCol, lightcolour, layer_pigment_colour, relativeIor); + ComputeSpecularColour (finish, lightsourceray.Direction, -eye.Direction, layer_normal, tmpCol, + tempLightColour, layer_pigment_colour, relativeIor); } if(finish->Irid > 0.0) diff --git a/source/core/scene/object.cpp b/source/core/scene/object.cpp index 6da0cabd2..bb1caaa93 100644 --- a/source/core/scene/object.cpp +++ b/source/core/scene/object.cpp @@ -713,6 +713,7 @@ ObjectPtr Copy_Object (ObjectPtr Old) New->Ph_Density = Old->Ph_Density; New->RadiosityImportance = Old->RadiosityImportance; + New->RadiosityImportanceSet = Old->RadiosityImportanceSet; // TODO FIXME - An explanation WHY this is important would be nice [CLi] New->LLights.clear(); // important @@ -832,7 +833,7 @@ ObjectBase::~ObjectBase() double ObjectBase::GetPotential (const Vector3d& p, bool subtractThreshold, TraceThreadData *threaddata) const { - POV_ASSERT (false); + POV_SHAPE_ASSERT (false); return 0.0; } diff --git a/source/core/scene/object.h b/source/core/scene/object.h index 989a22331..d6b78a0b4 100644 --- a/source/core/scene/object.h +++ b/source/core/scene/object.h @@ -173,7 +173,8 @@ class ObjectBase BoundingBox BBox; TRANSFORM *Trans; SNGL Ph_Density; - FloatSetting RadiosityImportance; + double RadiosityImportance; + bool RadiosityImportanceSet; unsigned int Flags; #ifdef OBJECT_DEBUG_HELPER @@ -184,7 +185,7 @@ class ObjectBase ObjectBase(int t) : Type(t), Texture(NULL), Interior_Texture(NULL), interior(), Trans(NULL), - Ph_Density(0), RadiosityImportance(0.0), Flags(0) + Ph_Density(0), RadiosityImportance(0.0), RadiosityImportanceSet(false), Flags(0) { Make_BBox(BBox, -BOUND_HUGE/2.0, -BOUND_HUGE/2.0, -BOUND_HUGE/2.0, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE); } @@ -198,7 +199,8 @@ class ObjectBase ObjectBase(int t, ObjectBase& o, bool transplant) : Type(t), Texture(o.Texture), Interior_Texture(o.Interior_Texture), interior(o.interior), Trans(o.Trans), - Ph_Density(o.Ph_Density), RadiosityImportance(o.RadiosityImportance), Flags(o.Flags), + Ph_Density(o.Ph_Density), RadiosityImportance(o.RadiosityImportance), + RadiosityImportanceSet(o.RadiosityImportanceSet), Flags(o.Flags), Bound(o.Bound), Clip(o.Clip), LLights(o.LLights), BBox(o.BBox) { if (transplant) diff --git a/source/core/shape/cone.cpp b/source/core/shape/cone.cpp index 4bf486877..4dcb8a017 100644 --- a/source/core/shape/cone.cpp +++ b/source/core/shape/cone.cpp @@ -925,4 +925,135 @@ void Cone::Compute_BBox() Recompute_BBox(&BBox, Trans); } + + +/***************************************************************************** +* +* FUNCTION +* +* Cone_UVCoord +* +* INPUT +* +* OUTPUT +* +* RETURNS +* +* AUTHOR +* +* Jerome Grimbert +* +* DESCRIPTION +* +* - +* +* CHANGES +* +* - +* +******************************************************************************/ + +void Cone::UVCoord(Vector2d& Result, const Intersection *Inter, TraceThreadData *Thread) const +{ + CalcUV(Inter->IPoint, Result); +} + + +/***************************************************************************** +* +* FUNCTION +* +* CalcUV +* +* INPUT +* +* OUTPUT +* +* RETURNS +* +* AUTHOR +* +* Jerome Grimbert +* +* DESCRIPTION +* +* Calculate the u/v coordinate of a point on an cone/cylinder (inspired by lemon) +* +* CHANGES +* +* - +* +******************************************************************************/ + +void Cone::CalcUV(const Vector3d& IPoint, Vector2d& Result) const +{ + DBL len, x, y, z; + DBL phi, theta; + Vector3d P; + + // Transform the ray into the cone space. + MInvTransPoint(P, IPoint, Trans); + + // the center of UV coordinate is the <0,0> point + x = P[X]; + y = P[Y]; + + // Determine its angle from the point (1, 0, 0) in the x-y plane. + len = x * x + y * y; + + if ((P[Z]>(dist+EPSILON))&&(P[Z]<(1.0-EPSILON))) + { + // when not on a face, the range 0.25 to 0.75 is used (just plain magic 25% for face, no other reason, but it makes C-Lipka happy) + // phi = 0.25+0.5*(P[Z]-dist)/(1.0-dist); // <-- hgpovray was upside down to norm. Delete line if flip below holds. + phi = 0.75-0.5*(P[Z]-dist)/(1.0-dist); + } + else if (P[Z]>(dist+EPSILON)) + { + // the radii are changed (apex_radius is 1.0 for len) + // aka P[Z] is 1, use the apex_radius, from 75% to 100% (at the very center) + // phi = 1.0-(sqrt(len)/4.0); // <-- hgpovray was upside down to norm. Delete line if flip below holds. + phi = (sqrt(len)/4.0); + } + else + { + // aka P[Z] is dist, use the base_radius, from 0% (at the very center) to 25% + // phi = 0; + phi = 1.0; // <-- hgpovray was upside down to norm. Delete line if flip below holds. + if (base_radius) + { + // phi = sqrt(len)*apex_radius/(base_radius*4.0); // <-- hgpovray was upside down to norm. Delete line if flip below holds. + phi = 1.0-(sqrt(len)*apex_radius/(base_radius*4.0)); + } + } + + + if (len > EPSILON) + { + len = sqrt(len); + if (y == 0.0) + { + if (x > 0) + theta = 0.0; + else + theta = M_PI; + } + else + { + theta = acos(x / len); + if (y < 0.0) + theta = TWO_M_PI - theta; + } + + theta /= TWO_M_PI; // This will be from 0 to 1 + } + else + // This point is at one of the poles. Any value of xcoord will be ok... + theta = 0; + + Result[U] = theta; + Result[V] = phi; + +} + + } diff --git a/source/core/shape/cone.h b/source/core/shape/cone.h index f689904ad..011e2ff48 100644 --- a/source/core/shape/cone.h +++ b/source/core/shape/cone.h @@ -80,7 +80,7 @@ class Cone : public ObjectBase virtual bool All_Intersections(const Ray&, IStack&, TraceThreadData *); virtual bool Inside(const Vector3d&, TraceThreadData *) const; virtual void Normal(Vector3d&, Intersection *, TraceThreadData *) const; - // virtual void UVCoord(Vector2d&, const Intersection *, TraceThreadData *) const; // TODO FIXME - why is there no UV-mapping for this simple object? + virtual void UVCoord(Vector2d&, const Intersection *, TraceThreadData *) const; virtual void Translate(const Vector3d&, const TRANSFORM *); virtual void Rotate(const Vector3d&, const TRANSFORM *); virtual void Scale(const Vector3d&, const TRANSFORM *); @@ -91,6 +91,7 @@ class Cone : public ObjectBase void Compute_Cylinder_Data(); protected: int Intersect(const BasicRay& ray, CONE_INT *Intersection, TraceThreadData *Thread) const; + void CalcUV(const Vector3d& IPoint, Vector2d& Result) const; }; } diff --git a/source/core/shape/lemon.cpp b/source/core/shape/lemon.cpp index e8fa64f14..fbf10ac1a 100644 --- a/source/core/shape/lemon.cpp +++ b/source/core/shape/lemon.cpp @@ -826,24 +826,24 @@ void Lemon::CalcUV(const Vector3d& IPoint, Vector2d& Result) const if ((P[Z]>EPSILON)&&(P[Z]<(1.0-EPSILON))) { // when not on a face, the range 0.25 to 0.75 is used (just plain magic 25% for face, no other reason, but it makes C-Lipka happy) - phi = 0.25+0.5*P[Z]; + phi = 0.75-0.5*P[Z]; } else if (P[Z]>EPSILON) { - // aka P[Z] is 1, use the apex_radius, from 75% to 100% (at the very center) - phi = 1.0; + // aka P[Z] is 0, use the apex_radius, from 75% to 100% (at the very center) + phi = 0.0; if (apex_radius) { - phi = 1.0-(sqrt(len)/(apex_radius*4)); + phi = sqrt(len)/(apex_radius*4); } } else { - // aka P[Z] is 0, use the base_radius, from 0% (at the very center) to 25% - phi = 0; + // aka P[Z] is 1, use the base_radius, from 0% (at the very center) to 25% + phi = 1.0; if (base_radius) { - phi = sqrt(len)/(base_radius*4); + phi = 1.0-(sqrt(len)/(base_radius*4)); } } diff --git a/source/core/shape/quadric.cpp b/source/core/shape/quadric.cpp index 9505747d7..29b446f0f 100644 --- a/source/core/shape/quadric.cpp +++ b/source/core/shape/quadric.cpp @@ -837,7 +837,7 @@ void Quadric::Compute_BBox(Vector3d& ClipMin, Vector3d& ClipMax) { if (D != 0.0) { - T1[X] = J / (2.0 * D); + T1[X] = -J / (2.0 * D); } else { @@ -853,7 +853,7 @@ void Quadric::Compute_BBox(Vector3d& ClipMin, Vector3d& ClipMax) { if (G != 0.0) { - T1[Y] = J / (2.0 * G); + T1[Y] = -J / (2.0 * G); } else { @@ -869,7 +869,7 @@ void Quadric::Compute_BBox(Vector3d& ClipMin, Vector3d& ClipMax) { if (I != 0.0) { - T1[Z] = J / (2.0 * I); + T1[Z] = -J / (2.0 * I); } else { @@ -882,7 +882,7 @@ void Quadric::Compute_BBox(Vector3d& ClipMin, Vector3d& ClipMax) D += A * T1[X]; G += E * T1[Y]; I += H * T1[Z]; - J -= T1[X]*(A*T1[X] + 2.0*D) + T1[Y]*(E*T1[Y] + 2.0*G) + T1[Z]*(H*T1[Z] + 2.0*I); + J -= T1[X]*(A*T1[X] - 2.0*D) + T1[Y]*(E*T1[Y] - 2.0*G) + T1[Z]*(H*T1[Z] - 2.0*I); } else { diff --git a/source/core/shape/spheresweep.cpp b/source/core/shape/spheresweep.cpp index 5895e2e54..a418d7fdc 100644 --- a/source/core/shape/spheresweep.cpp +++ b/source/core/shape/spheresweep.cpp @@ -598,7 +598,7 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm break; default: - POV_ASSERT(false); + POV_SHAPE_ASSERT(false); break; } @@ -1522,6 +1522,10 @@ void SphereSweep::Compute() } } break; + + default: + POV_SHAPE_ASSERT (false); + break; } // Pre-calculate several constants diff --git a/source/core/shape/truetype.cpp b/source/core/shape/truetype.cpp index 6832ccf44..ab380dd84 100644 --- a/source/core/shape/truetype.cpp +++ b/source/core/shape/truetype.cpp @@ -667,7 +667,7 @@ void TrueType::ProcessNewTTF(CSG *Object, TrueTypeFont *ffile, const UCS2 *text_ #ifdef TTF_DEBUG // TODO - text_string is an UCS2 strings, while Debug_Info will expect char strings. - #error broken code + #error "broken code" if (filename) { Debug_Info("TTF parsing of \"%s\" from %s complete\n", text_string, filename); @@ -1672,6 +1672,7 @@ GlyphPtr ExtractGlyphInfo(TrueTypeFont *ffile, unsigned int glyph_index, unsigne GlyphPtr glyph; ttglyph = ExtractGlyphOutline(ffile, glyph_index, c); + POV_SHAPE_ASSERT (ttglyph); /* * Convert the glyph outline information from TrueType layout into a more @@ -1684,8 +1685,7 @@ GlyphPtr ExtractGlyphInfo(TrueTypeFont *ffile, unsigned int glyph_index, unsigne /* Free up outline information */ - if (ttglyph) - delete ttglyph; + delete ttglyph; #ifdef TTF_DEBUG3 int i, j; diff --git a/source/core/support/bsptree.cpp b/source/core/support/bsptree.cpp index 3ef801aa1..fbc0af86f 100644 --- a/source/core/support/bsptree.cpp +++ b/source/core/support/bsptree.cpp @@ -96,7 +96,9 @@ BSPTree::~BSPTree() { } +#if BSP_WRITETREE static FILE *gFile = NULL; +#endif bool BSPTree::operator()(const BasicRay& ray, Intersect& isect, Mailbox& mailbox, double maxdist) { @@ -289,12 +291,10 @@ void BSPTree::build(const Progress& progress, const Objects& objects, #if BSP_WRITEBOUNDS FILE *bb = fopen(string(tempstr + ".bounds").c_str(), "w"); -#else - FILE *bb = NULL; -#endif if(bb != NULL) fprintf(bb, "%d\n", objects.size()); +#endif // find bounding box containing all objects for(unsigned int i = 0; i < objects.size(); i++) @@ -309,12 +309,15 @@ void BSPTree::build(const Progress& progress, const Objects& objects, indices[i] = i; +#if BSP_WRITEBOUNDS if(bb != NULL) fprintf(bb, "%f %f %f %f %f %f\n", objects.GetMin(X, i), objects.GetMin(Y, i), objects.GetMin(Z, i), objects.GetMax(X, i), objects.GetMax(Y, i), objects.GetMax(Z, i)); +#endif } +#if BSP_WRITEBOUNDS if(bb != NULL) { fprintf(bb, "%f %f %f %f %f %f\n", @@ -322,6 +325,7 @@ void BSPTree::build(const Progress& progress, const Objects& objects, fflush(bb); fclose(bb); } +#endif // remember bounding box for intersection testing bmin = Vector3d(bbox.pmin[X], bbox.pmin[Y], bbox.pmin[Z]); @@ -329,13 +333,13 @@ void BSPTree::build(const Progress& progress, const Objects& objects, #if BSP_WRITETREE gFile = fopen(string(tempstr + ".tree").c_str(), "w"); -#endif if(gFile != NULL) { fprintf(gFile, "> %f %f %f %f %f %f\n", bbox.pmin[X], bbox.pmin[Y], bbox.pmin[Z], bbox.pmax[X], bbox.pmax[Y], bbox.pmax[Z]); fprintf(gFile, "T %d\n", objects.size()); } +#endif // recursively build BSP tree nodes.push_back(Node()); @@ -350,8 +354,10 @@ void BSPTree::build(const Progress& progress, const Objects& objects, } catch(pov_base::Exception& e) { +#if BSP_WRITETREE if (gFile != NULL) fclose (gFile); +#endif if ((e.codevalid() != false) && (e.code() == kFileDataErr)) { int line = 0; @@ -378,11 +384,13 @@ void BSPTree::build(const Progress& progress, const Objects& objects, BuildRecursive(progress, objects, 0, 0, (unsigned int) indices.size(), bbox, maxDepth); #endif +#if BSP_WRITETREE if(gFile != NULL) { fflush(gFile); fclose(gFile); } +#endif // memory was only needed for building splits[X].clear(); @@ -441,16 +449,20 @@ void BSPTree::BuildRecursive(const Progress& progress, const Objects& objects, u progress(lastProgressNodeCounter); } +#if BSP_WRITETREE if(gFile != NULL) fprintf(gFile, "%*s", (maxDepth - maxlevel) * 2, ""); +#endif unsigned int cnt = indexend - indexbegin; // number of objects // stop if there are no more objects if(cnt == 0) { +#if BSP_WRITETREE if(gFile != NULL) fprintf(gFile, "*\n"); +#endif nodes[inode].type = Node::Object; nodes[inode].data = Node::Empty; @@ -621,6 +633,7 @@ void BSPTree::BuildRecursive(const Progress& progress, const Objects& objects, u sort(splits[bestaxis].begin(), splits[bestaxis].begin() + bestsplit, ci); sort(splits[bestaxis].begin() + bestsplit, splits[bestaxis].begin() + bestscnt, ci); +#if BSP_WRITETREE if(gFile != NULL) { fprintf(gFile, "| %c = %g ", (int)('x' + bestaxis), bestplane); @@ -628,6 +641,7 @@ void BSPTree::BuildRecursive(const Progress& progress, const Objects& objects, u cell.pmin[0], cell.pmin[1], cell.pmin[2], cell.pmax[0], cell.pmax[1], cell.pmax[2]); } +#endif unsigned int begin = (unsigned int) indices.size(); for (vector::iterator it = splits[bestaxis].begin(), en = it + bestsplit; it != en; ) @@ -669,6 +683,7 @@ void BSPTree::SetObjectNode(unsigned int inode, unsigned int indexbegin, unsigne { unsigned int count = indexend - indexbegin; +#if BSP_WRITETREE if(gFile != NULL) { fprintf(gFile, "# (%d) ", count); @@ -676,6 +691,7 @@ void BSPTree::SetObjectNode(unsigned int inode, unsigned int indexbegin, unsigne fprintf(gFile, " %d", indices[i]); fprintf(gFile, "\n"); } +#endif objectNodeCounter++; @@ -805,8 +821,10 @@ void BSPTree::ReadRecursive(const Progress& progress, FILE *infile, unsigned int if(fscanf(infile, " %u %f\n", &bestaxis, &bestplane) != 2) // read axis and plane throw POV_EXCEPTION(kFileDataErr, "Expected axis and plane whilst reading node file"); +#if BSP_WRITETREE if(gFile != NULL) fprintf(gFile, "%*s| %c = %g\n", level * 2, "", 'x' + bestaxis, bestplane); +#endif // create child nodes nodes.push_back(Node()); @@ -837,8 +855,10 @@ void BSPTree::ReadRecursive(const Progress& progress, FILE *infile, unsigned int if (cnt == 0) { +#if BSP_WRITETREE if(gFile != NULL) fprintf(gFile, "%*s*\n", level * 2, ""); +#endif nodes[inode].type = Node::Object; nodes[inode].data = Node::Empty; nodes[inode].index = 0; @@ -863,8 +883,10 @@ void BSPTree::ReadRecursive(const Progress& progress, FILE *infile, unsigned int fscanf(infile, "\n"); +#if BSP_WRITETREE if(gFile != NULL) fprintf(gFile, "%*s", level * 2, ""); +#endif SetObjectNode(inode, 0, (unsigned int) ind.size()); } diff --git a/source/core/support/imageutil.cpp b/source/core/support/imageutil.cpp index 79fcc04b3..bee33c732 100644 --- a/source/core/support/imageutil.cpp +++ b/source/core/support/imageutil.cpp @@ -91,9 +91,6 @@ static void norm_dist(DBL *factors, DBL x, DBL y); static void cubic(DBL *factors, DBL x); static void Interp(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul); static void InterpolateBicubic(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul); -static void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index); // TODO ALPHA - caller should decide whether to prefer premultiplied or non-premultiplied alpha -static void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul); -static int map_pos(const Vector3d& EPoint, const BasicPattern* pPattern, DBL *xcoor, DBL *ycoor); /* * 2-D to 3-D Procedural Texture Mapping of a Bitmapped Image onto an Object: @@ -157,7 +154,7 @@ bool image_map(const Vector3d& EPoint, const PIGMENT *Pigment, TransColour& colo else { RGBFTColour rgbft; - image_colour_at(dynamic_cast(Pigment->pattern.get())->pImage, xcoor, ycoor, rgbft, ®_number, false); + image_colour_at(dynamic_cast(Pigment->pattern.get())->pImage, xcoor, ycoor, rgbft, ®_number, false); colour = ToTransColour(rgbft); return true; } @@ -203,7 +200,7 @@ TEXTURE *material_map(const Vector3d& EPoint, const TEXTURE *Texture) Material_Number = 0; else { - image_colour_at(dynamic_cast(Texture->pattern.get())->pImage, xcoor, ycoor, colour, ®_number); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha + image_colour_at(dynamic_cast(Texture->pattern.get())->pImage, xcoor, ycoor, colour, ®_number); // TODO ALPHA - we should decide whether we prefer premultiplied or non-premultiplied alpha if(reg_number == -1) Material_Number = (int)(colour.red() * 255.0); @@ -247,7 +244,7 @@ void bump_map(const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal) Vector3d xprime, yprime, zprime; DBL Length; DBL Amount = Tnormal->Amount; - const ImageData *image = dynamic_cast(Tnormal->pattern.get())->pImage; + const ImageData *image = dynamic_cast(Tnormal->pattern.get())->pImage; // going to have to change this // need to know if bump point is off of image for all 3 points @@ -368,7 +365,7 @@ DBL image_pattern(const Vector3d& EPoint, const BasicPattern* pPattern) DBL xcoor = 0.0, ycoor = 0.0; int index = -1; RGBFTColour colour; - const ImageData *image = dynamic_cast(pPattern)->pImage; + const ImageData *image = dynamic_cast(pPattern)->pImage; DBL Value; colour.Clear(); @@ -425,7 +422,7 @@ DBL image_pattern(const Vector3d& EPoint, const BasicPattern* pPattern) * ******************************************************************************/ -static void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index) +void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index) { // TODO ALPHA - caller should decide whether to prefer premultiplied or non-premultiplied alpha @@ -434,7 +431,7 @@ static void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTC image_colour_at(image, xcoor, ycoor, colour, index, image->data->IsPremultiplied()); } -static void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul) +void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul) { *index = -1; @@ -970,9 +967,9 @@ static int planar_image_map(const Vector3d& EPoint, const ImageData *image, DBL * ******************************************************************************/ -static int map_pos(const Vector3d& EPoint, const BasicPattern* pPattern, DBL *xcoor, DBL *ycoor) +int map_pos(const Vector3d& EPoint, const BasicPattern* pPattern, DBL *xcoor, DBL *ycoor) { - const ImageData *image = dynamic_cast(pPattern)->pImage; + const ImageData *image = dynamic_cast(pPattern)->pImage; // Now determine which mapper to use. diff --git a/source/core/support/imageutil.h b/source/core/support/imageutil.h index 3655667f8..501127f98 100644 --- a/source/core/support/imageutil.h +++ b/source/core/support/imageutil.h @@ -116,12 +116,17 @@ class ImageData ~ImageData(); }; +typedef ImageData *ImageDataPtr; + DBL image_pattern(const Vector3d& EPoint, const BasicPattern* pPattern); bool image_map(const Vector3d& EPoint, const PIGMENT *Pigment, TransColour& colour); TEXTURE *material_map(const Vector3d& IPoint, const TEXTURE *Texture); void bump_map(const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal); +void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index); // TODO ALPHA - caller should decide whether to prefer premultiplied or non-premultiplied alpha +void image_colour_at(const ImageData *image, DBL xcoor, DBL ycoor, RGBFTColour& colour, int *index, bool premul); HF_VAL image_height_at(const ImageData *image, int x, int y); bool is_image_opaque(const ImageData *image); +int map_pos(const Vector3d& EPoint, const BasicPattern* pPattern, DBL *xcoor, DBL *ycoor); ImageData *Copy_Image(ImageData *old); ImageData *Create_Image(void); void Destroy_Image(ImageData *image); diff --git a/source/core/support/octree.cpp b/source/core/support/octree.cpp index 4a9410bde..2fb7f9a93 100644 --- a/source/core/support/octree.cpp +++ b/source/core/support/octree.cpp @@ -107,24 +107,24 @@ namespace pov // (note that these don't necessarily catch all possible quirks; they should be quite reliable though) #if(C99_COMPATIBLE_RADIOSITY == 0) #if( (INT_MAX != SIGNED32_MAX) || (INT_MIN + SIGNED32_MAX != -1) ) - #error 'int' is not 32 bit or does not use two's complement encoding; try a different C99_COMPATIBLE_RADIOSITY setting in config.h + #error "'int' is not 32 bit or does not use two's complement encoding; try a different C99_COMPATIBLE_RADIOSITY setting in config.h" #endif #if(FLT_RADIX != 2) - #error 'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h + #error "'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h" #endif #if(FLT_MANT_DIG != 24) - #error 'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h + #error "'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h" #endif #if(FLT_MAX_EXP != 128) - #error 'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h + #error "'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h" #endif #if(FLT_MIN_EXP != -125) - #error 'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h + #error "'float' does not conform to IEEE 754 single-precision format; try a different C99_COMPATIBLE_RADIOSITY setting in config.h" #endif #else #if(FLT_RADIX != 2) // logb family of functions will not work as expected - #error floating point arithmetic uses an uncommon radix; this file will not compile on your machine + #error "floating point arithmetic uses an uncommon radix; this file will not compile on your machine" #endif #endif @@ -1129,7 +1129,7 @@ bool ot_write_block(OT_BLOCK *bl, void *fd) // must be passed as void * for comp #if (NUM_COLOUR_CHANNELS == 3) bl->Illuminance.Red(), bl->Illuminance.Green(), bl->Illuminance.Blue(), #else - #error TODO! + #error "TODO!" #endif bl->Harmonic_Mean_Distance, @@ -1328,7 +1328,7 @@ bool ot_read_file(OT_NODE **root, IStream *fd, const OT_READ_PARAM* param, OT_RE &bl.Nearest_Distance, to_nearest_string ); bl.Illuminance = ToMathColour(tempCol); #else - #error TODO! + #error "TODO!" #endif // TODO FIXME - read Quality and Brilliance diff --git a/source/frontend/processrenderoptions.cpp b/source/frontend/processrenderoptions.cpp index c81ec1329..006ae62cf 100644 --- a/source/frontend/processrenderoptions.cpp +++ b/source/frontend/processrenderoptions.cpp @@ -360,6 +360,10 @@ ProcessRenderOptions::~ProcessRenderOptions() int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, char *param, POVMSObjectPtr obj) { POVMSAttributeList list; + POVMSAttribute attr; + POVMSObject decobj; + POVMSObject cmdobj; + POVMSType typeKey; double floatval = 0.0; int intval = 0; int intval2 = 0; @@ -369,11 +373,14 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha { case kPOVAttrib_Palette: case kPOVAttrib_VideoMode: + while(isspace(*param)) param++; err = POVMSUtil_SetInt(obj, option->key, tolower(*param)); break; + case kPOVAttrib_DitherMethod: + while(isspace(*param)) param++; err = ParseParameterCode(DitherMethodTable, param, &intval); @@ -382,38 +389,32 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha else ParseError("Unrecognized dither method '%s'.", param); break; + case kPOVAttrib_OutputFileType: + while(isspace(*param)) param++; err = ParseFileType(*param, option->key, &intval); if (err == kNoErr) err = POVMSUtil_SetInt(obj, option->key, intval); break; + case kPOVAttrib_IncludeIni: case kPOVAttrib_LibraryPath: - POVMSAttribute attr; - if(err == kNoErr) - { - // parse INI file (recursive) - if(option->key == kPOVAttrib_IncludeIni) - err = ParseFile(param, obj); + // parse INI file (recursive) + if(option->key == kPOVAttrib_IncludeIni) + err = ParseFile(param, obj); - // create list if it isn't there - if(err == kNoErr) - { - if(POVMSObject_Exist(obj, option->key) == kFalseErr) - err = POVMSAttrList_New(&list); - else if(POVMSObject_Exist(obj, option->key) != kNoErr) - err = kObjectAccessErr; - else - err = POVMSObject_Get(obj, &list, option->key); - } - } - else + // create list if it isn't there + if(err == kNoErr) { - ParseError("File name or path parameter expected for option '%s', found '%s'.", option->keyword, param); - err = kParamErr; + if(POVMSObject_Exist(obj, option->key) == kFalseErr) + err = POVMSAttrList_New(&list); + else if(POVMSObject_Exist(obj, option->key) != kNoErr) + err = kObjectAccessErr; + else + err = POVMSObject_Get(obj, &list, option->key); } // add path or file to list @@ -430,8 +431,8 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha if(err == kNoErr) err = POVMSObject_Set(obj, &list, option->key); break; + case kPOVAttrib_Declare: - POVMSObject decobj; // create list if it isn't there if(POVMSObject_Exist(obj, option->key) == kFalseErr) @@ -474,13 +475,13 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha if(err == kNoErr) err = POVMSObject_Set(obj, &list, option->key); break; + case kPOVAttrib_FatalErrorCommand: case kPOVAttrib_PostFrameCommand: case kPOVAttrib_PostSceneCommand: case kPOVAttrib_PreFrameCommand: case kPOVAttrib_PreSceneCommand: case kPOVAttrib_UserAbortCommand: - POVMSObject cmdobj; if(POVMSObject_Exist(obj, option->key) == kNoErr) err = POVMSObject_Get(obj, &cmdobj, option->key); @@ -507,10 +508,11 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha if(err == kNoErr) err = POVMSObject_Set(obj, &cmdobj, option->key); break; + case kPOVAttrib_AntialiasGamma: case kPOVAttrib_DisplayGamma: case kPOVAttrib_FileGamma: - POVMSType typeKey; + switch (option->key) { case kPOVAttrib_AntialiasGamma: typeKey = kPOVAttrib_AntialiasGammaType; break; @@ -537,6 +539,8 @@ int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, cha int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, char *param, POVMSObjectPtr obj, bool) { + POVMSAttributeList list; + POVMSAttribute attr; int intval = 0; int intval2 = 0; int err = 0; @@ -547,6 +551,7 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha switch(option->key) { case kPOVAttrib_Display: + if(param[0] != '\0') { err = POVMSUtil_SetInt(obj, kPOVAttrib_VideoMode, (int)toupper(param[0])); @@ -554,14 +559,18 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha err = POVMSUtil_SetInt(obj, kPOVAttrib_Palette, (int)toupper(param[1])); } break; + case kPOVAttrib_DitherMethod: + err = ParseParameterCode(DitherMethodTable, param, &intval); if (err == kNoErr) err = POVMSUtil_SetInt(obj, option->key, intval); else ParseError("Unrecognized dither method '%s'.", param); break; + case kPOVAttrib_OutputFileType: + err = ParseFileType(*param, option->key, &intval, &has16BitGrayscale); if (err == kNoErr) { @@ -613,25 +622,16 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha } } break; + case kPOVAttrib_LibraryPath: - POVMSAttributeList list; - POVMSAttribute attr; - if(err == kNoErr) - { - // create list if it isn't there - if(POVMSObject_Exist(obj, option->key) == kFalseErr) - err = POVMSAttrList_New(&list); - else if(POVMSObject_Exist(obj, option->key) != kNoErr) - err = kObjectAccessErr; - else - err = POVMSObject_Get(obj, &list, option->key); - } + // create list if it isn't there + if(POVMSObject_Exist(obj, option->key) == kFalseErr) + err = POVMSAttrList_New(&list); + else if(POVMSObject_Exist(obj, option->key) != kNoErr) + err = kObjectAccessErr; else - { - ParseError("File name or path parameter expected for switch '%s', found '%s'.", option->command, param); - err = kParamErr; - } + err = POVMSObject_Get(obj, &list, option->key); // add path or file to list if(err == kNoErr) @@ -647,7 +647,9 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha if(err == kNoErr) err = POVMSObject_Set(obj, &list, option->key); break; + case kPOVAttrib_TestAbortCount: + if((*param) == 0) break; if(sscanf(param, "%d", &intval) == 1) @@ -666,6 +668,8 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, POVMSObjectPtr obj, OTextStream *file) { POVMSAttributeList list; + POVMSObject decobj; + POVMSObject cmdobj; POVMSFloat floatval; POVMSInt intval; int err = 0; @@ -679,6 +683,7 @@ int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, PO { case kPOVAttrib_Palette: case kPOVAttrib_VideoMode: + if(POVMSUtil_GetInt(obj, option->key, &intval) == 0) { chr = intval; @@ -686,7 +691,9 @@ int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, PO file->printf("%s=%c\n", option->keyword, chr); } break; + case kPOVAttrib_OutputFileType: + if(POVMSUtil_GetInt(obj, option->key, &intval) == 0) { chr = UnparseFileType(intval); @@ -694,10 +701,12 @@ int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, PO file->printf("%s=%c\n", option->keyword, chr); } break; + case kPOVAttrib_IncludeIni: + break; + case kPOVAttrib_Declare: - POVMSObject decobj; err = POVMSObject_Get(obj, &list, option->key); if(err != 0) @@ -733,7 +742,9 @@ int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, PO } } break; + case kPOVAttrib_LibraryPath: + err = POVMSObject_Get(obj, &list, option->key); if(err != 0) break; @@ -765,13 +776,13 @@ int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, PO } } break; + case kPOVAttrib_FatalErrorCommand: case kPOVAttrib_PostFrameCommand: case kPOVAttrib_PostSceneCommand: case kPOVAttrib_PreFrameCommand: case kPOVAttrib_PreSceneCommand: case kPOVAttrib_UserAbortCommand: - POVMSObject cmdobj; err = POVMSObject_Get(obj, &cmdobj, option->key); if(err != 0) diff --git a/source/parser/fncode.cpp b/source/parser/fncode.cpp index 7c36949c5..49c4bbca5 100644 --- a/source/parser/fncode.cpp +++ b/source/parser/fncode.cpp @@ -447,9 +447,9 @@ void FNCode_Copy(FunctionCode *f, FunctionCode *fnew) * ******************************************************************************/ +#if (DEBUG_FLOATFUNCTION == 1) void FNCode::SetFlag(unsigned int flag, char *str) { -#if (DEBUG_FLOATFUNCTION == 1) if(flag == 1) { if(asm_input != NULL) @@ -462,12 +462,8 @@ void FNCode::SetFlag(unsigned int flag, char *str) POV_FREE(asm_output); asm_output = POV_STRDUP(str); } -#else - // silence compiler warnings - flag = 0; - str = NULL; -#endif } +#endif /***************************************************************************** @@ -500,7 +496,7 @@ void FNCode::SetFlag(unsigned int flag, char *str) void FNCode::compile_recursive(ExprNode *expr) { - POV_ASSERT(expr != NULL); + POV_PARSER_ASSERT(expr != NULL); unsigned int local_k = 0; diff --git a/source/parser/fncode.h b/source/parser/fncode.h index 8a63d1443..7292e762a 100644 --- a/source/parser/fncode.h +++ b/source/parser/fncode.h @@ -121,7 +121,11 @@ class FNCode void Parameter(); void Compile(ExprNode *); + +#if (DEBUG_FLOATFUNCTION == 1) void SetFlag(unsigned int, char *); +#endif + private: FunctionCode *function; Parser *parser; diff --git a/source/parser/parser.cpp b/source/parser/parser.cpp index b3b41c08f..956b234d5 100644 --- a/source/parser/parser.cpp +++ b/source/parser/parser.cpp @@ -155,6 +155,12 @@ Parser::Parser(shared_ptr sd, bool useclk, DBL clk) : mBetaFeatureFlags.realTimeRaytracing = true; } +Parser::~Parser() +{ + // NB: We need to keep fnVMContext around until all functions have been destroyed. + delete fnVMContext; +} + /* Parse the file. */ void Parser::Run() { @@ -192,12 +198,12 @@ void Parser::Run() if(i->second[0] == '\"') { string tmp(i->second, 1, i->second.length() - 2); - Temp_Entry = Add_Symbol(1, const_cast(i->first.c_str()), STRING_ID_TOKEN); + Temp_Entry = Add_Symbol(SYM_TABLE_GLOBAL, const_cast(i->first.c_str()), STRING_ID_TOKEN); Temp_Entry->Data = String_Literal_To_UCS2(const_cast(tmp.c_str()), false); } else { - Temp_Entry = Add_Symbol(1, const_cast(i->first.c_str()), FLOAT_ID_TOKEN); + Temp_Entry = Add_Symbol(SYM_TABLE_GLOBAL, const_cast(i->first.c_str()), FLOAT_ID_TOKEN); Temp_Entry->Data = Create_Float(); *(reinterpret_cast(Temp_Entry->Data)) = atof(i->second.c_str()); } @@ -459,9 +465,6 @@ void Parser::Cleanup() Brace_Stack = NULL; Destroy_Random_Generators(); - - // NB: We need to keep fnVMContext around until all functions have been destroyed. - delete fnVMContext; } void Parser::Stopped() @@ -1068,7 +1071,7 @@ void Parser::Parse_Blob_Element_Mods(Blob_Element *Element) Link_Textures(&Element->Texture, Local_Texture); END_CASE - CASE3 (PIGMENT_TOKEN, TNORMAL_TOKEN, FINISH_TOKEN) + CASE3 (PIGMENT_TOKEN, NORMAL_TOKEN, FINISH_TOKEN) if (Element->Texture == NULL) { Element->Texture = Copy_Textures(Default_Texture); @@ -1088,7 +1091,7 @@ void Parser::Parse_Blob_Element_Mods(Blob_Element *Element) Parse_End (); END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin (); Parse_Tnormal(&Element->Texture->Tnormal); Parse_End (); @@ -1353,17 +1356,15 @@ void Parser::Parse_Camera (Camera& Cam) Parse_Begin (); - EXPECT + EXPECT_ONE CASE (CAMERA_ID_TOKEN) Cam = *reinterpret_cast(Token.Data); if (sceneData->EffectiveLanguageVersion() >= 350) only_mods = true; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -1904,7 +1905,7 @@ void Parser::Parse_Camera (Camera& Cam) } END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin (); Parse_Tnormal(&(New.Tnormal)); Parse_End (); @@ -2099,7 +2100,7 @@ bool Parser::Parse_Camera_Mods(Camera& New) Compose_Transforms(New.Trans, &Local_Trans); END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin(); Parse_Tnormal(&(New.Tnormal)); Parse_End(); @@ -2308,15 +2309,13 @@ ObjectPtr Parser::Parse_Cone () Parse_Vector(Object->base); Parse_Comma (); Object->base_radius = Parse_Float(); - EXPECT + EXPECT_ONE CASE(OPEN_TOKEN) Clear_Flag(Object, CLOSED_FLAG); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -2366,15 +2365,13 @@ ObjectPtr Parser::Parse_Cylinder () Object->apex_radius = Parse_Float(); Object->base_radius = Object->apex_radius; - EXPECT + EXPECT_ONE CASE(OPEN_TOKEN) Clear_Flag(Object, CLOSED_FLAG); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -2425,7 +2422,7 @@ ObjectPtr Parser::Parse_Disc () tmpf = Parse_Float(); Parse_Comma (); Object->oradius2 = tmpf * tmpf; - EXPECT + EXPECT_ONE CASE_FLOAT tmpf = Parse_Float(); Object->iradius2 = tmpf * tmpf; @@ -2433,7 +2430,6 @@ ObjectPtr Parser::Parse_Disc () OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -2999,11 +2995,11 @@ ObjectPtr Parser::Parse_Lathe() /* Read points (x : radius; y : height; z : not used). */ + Parse_Comma(); + AlreadyWarned = false; for (i = 0; i < Object->Number; i++) { - Parse_Comma(); - Parse_UV_Vect(Points[i]); switch (Object->Spline_Type) @@ -3050,6 +3046,10 @@ ObjectPtr Parser::Parse_Lathe() break; } + + // NB we allow for a trailing comma at the end of the list, + // to facilitate auto-generation of lists. + Parse_Comma(); } /* Compute spline segments. */ @@ -3125,15 +3125,13 @@ ObjectPtr Parser::Parse_Lemon () Error("All radii must be positive"); } - EXPECT + EXPECT_ONE CASE(OPEN_TOKEN) Clear_Flag(Object, CLOSED_FLAG); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -3466,7 +3464,7 @@ ObjectPtr Parser::Parse_Light_Source () Set_Flag(Object, PH_PASSTHRU_FLAG); END_CASE - CASE (FILL_LIGHT_TOKEN) + CASE (SHADOWLESS_TOKEN) Object->Light_Type = FILL_LIGHT_SOURCE; END_CASE @@ -4409,51 +4407,45 @@ void Parser::Parse_Mesh2 (Mesh* Object) Triangles[i].P3 = c; /* look for a texture index */ - EXPECT + EXPECT_ONE CASE_FLOAT Triangles[i].Texture = Parse_Float(); Parse_Comma(); if (Triangles[i].Texture >= number_of_textures || Triangles[i].Texture < 0) Error("Texture index out of range in mesh2."); - EXIT END_CASE OTHERWISE Triangles[i].Texture = -1; fully_textured = false; - EXIT UNGET END_CASE END_EXPECT /* look for a texture index */ - EXPECT + EXPECT_ONE CASE_FLOAT Triangles[i].Texture2 = Parse_Float(); Parse_Comma(); if (Triangles[i].Texture2 >= number_of_textures || Triangles[i].Texture2 < 0) Error("Texture index out of range in mesh2."); Triangles[i].ThreeTex = true; - EXIT END_CASE OTHERWISE Triangles[i].Texture2 = -1; - EXIT UNGET END_CASE END_EXPECT /* look for a texture index */ - EXPECT + EXPECT_ONE CASE_FLOAT Triangles[i].Texture3 = Parse_Float(); Parse_Comma(); if (Triangles[i].Texture3 >= number_of_textures || Triangles[i].Texture3 < 0) Error("Texture index out of range in mesh2."); Triangles[i].ThreeTex = true; - EXIT END_CASE OTHERWISE Triangles[i].Texture3 = -1; - EXIT UNGET END_CASE END_EXPECT @@ -4995,7 +4987,7 @@ ObjectPtr Parser::Parse_Parametric(void) PrecompDepth= Parse_Float(); Parse_Comma(); - EXPECT + EXPECT_ONE CASE(VECTOR_FUNCT_TOKEN) if(Token.Function_Id != X_TOKEN) { @@ -5003,18 +4995,16 @@ ObjectPtr Parser::Parse_Parametric(void) } else PrecompFlag |= 1; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT Parse_Comma(); - EXPECT + EXPECT_ONE CASE(VECTOR_FUNCT_TOKEN) if(Token.Function_Id != Y_TOKEN) { @@ -5022,18 +5012,16 @@ ObjectPtr Parser::Parse_Parametric(void) } else PrecompFlag |= 2; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT Parse_Comma(); - EXPECT + EXPECT_ONE CASE(VECTOR_FUNCT_TOKEN) if(Token.Function_Id != Z_TOKEN) { @@ -5041,12 +5029,10 @@ ObjectPtr Parser::Parse_Parametric(void) } else PrecompFlag |= 4; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT END_CASE @@ -5367,11 +5353,15 @@ ObjectPtr Parser::Parse_Polygon() Points = reinterpret_cast(POV_MALLOC((Number+1)*sizeof(Vector3d), "temporary polygon points")); + Parse_Comma(); + for (i = 0; i < Number; i++) { - Parse_Comma(); - Parse_Vector(Points[i]); + + // NB we allow for a trailing comma at the end of the list, + // to facilitate auto-generation of lists. + Parse_Comma(); } /* Check for closed polygons. */ @@ -5565,24 +5555,26 @@ ObjectPtr Parser::Parse_Prism() /* Read points (x, y : coordinate of 2d point; z : not used). */ + Parse_Comma(); + for (i = 0; i < Object->Number; i++) { - Parse_Comma(); - Parse_UV_Vect(Points[i]); + + // NB we allow for a trailing comma at the end of the list, + // to facilitate auto-generation of lists. + Parse_Comma(); } /* Closed or not closed that's the question. */ - EXPECT + EXPECT_ONE CASE(OPEN_TOKEN) Clear_Flag(Object, CLOSED_FLAG); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -5910,10 +5902,10 @@ ObjectPtr Parser::Parse_Sor() /* Read points (x : radius; y : height; z : not used). */ + Parse_Comma(); + for (i = 0; i < Object->Number; i++) { - Parse_Comma(); - Parse_UV_Vect(Points[i]); if ((Points[i][X] < 0.0) || @@ -5921,19 +5913,21 @@ ObjectPtr Parser::Parse_Sor() { Error("Incorrect point in surface of revolution."); } + + // NB we allow for a trailing comma at the end of the list, + // to facilitate auto-generation of lists. + Parse_Comma(); } /* Closed or not closed that's the question. */ - EXPECT + EXPECT_ONE CASE(OPEN_TOKEN) Clear_Flag(Object, CLOSED_FLAG); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -6058,22 +6052,18 @@ ObjectPtr Parser::Parse_Sphere_Sweep() Object = new SphereSweep(); /* Get type of interpolation */ - EXPECT + EXPECT_ONE CASE(LINEAR_SPLINE_TOKEN) Object->Interpolation = LINEAR_SPHERE_SWEEP; - EXIT END_CASE CASE(CUBIC_SPLINE_TOKEN) Object->Interpolation = CATMULL_ROM_SPLINE_SPHERE_SWEEP; - EXIT END_CASE CASE(B_SPLINE_TOKEN) Object->Interpolation = B_SPLINE_SPHERE_SWEEP; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -6094,22 +6084,25 @@ ObjectPtr Parser::Parse_Sphere_Sweep() reinterpret_cast(POV_MALLOC(Object->Num_Modeling_Spheres * sizeof(SPHSWEEP_SPH), "sphere sweep modeling spheres")); + Parse_Comma(); + for (i = 0; i < Object->Num_Modeling_Spheres; i++) { - Parse_Comma(); Parse_Vector(Object->Modeling_Sphere[i].Center); Parse_Comma(); Object->Modeling_Sphere[i].Radius = Parse_Float(); + + // NB we allow for a trailing comma at the end of the list, + // to facilitate auto-generation of lists. + Parse_Comma(); } - EXPECT + EXPECT_ONE CASE(TOLERANCE_TOKEN) Object->Depth_Tolerance = Parse_Float(); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -6387,14 +6380,12 @@ ObjectPtr Parser::Parse_TrueType () if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL) return (reinterpret_cast(Object)); - EXPECT + EXPECT_ONE CASE(TTF_TOKEN) filename = Parse_C_String(true); - EXIT END_CASE CASE(INTERNAL_TOKEN) builtin_font = (int)Parse_Float(); - EXIT END_CASE OTHERWISE Expectation_Error ("ttf or internal"); @@ -6560,216 +6551,177 @@ ObjectPtr Parser::Parse_Object () { ObjectPtr Object = NULL; - EXPECT + EXPECT_ONE CASE (ISOSURFACE_TOKEN) Object = Parse_Isosurface (); - EXIT END_CASE CASE (PARAMETRIC_TOKEN) Object = Parse_Parametric (); - EXIT END_CASE CASE (JULIA_FRACTAL_TOKEN) Object = Parse_Julia_Fractal (); - EXIT END_CASE CASE (SPHERE_TOKEN) Object = Parse_Sphere (); - EXIT END_CASE CASE (SPHERE_SWEEP_TOKEN) Object = Parse_Sphere_Sweep (); - EXIT END_CASE CASE (PLANE_TOKEN) Object = Parse_Plane (); - EXIT END_CASE CASE (CONE_TOKEN) Object = Parse_Cone (); - EXIT END_CASE CASE (CYLINDER_TOKEN) Object = Parse_Cylinder (); - EXIT END_CASE CASE (DISC_TOKEN) Object = Parse_Disc (); - EXIT END_CASE CASE (QUADRIC_TOKEN) Object = Parse_Quadric (); - EXIT END_CASE CASE (CUBIC_TOKEN) Object = Parse_Poly (3); - EXIT END_CASE CASE (QUARTIC_TOKEN) Object = Parse_Poly (4); - EXIT END_CASE CASE (POLY_TOKEN) Object = Parse_Poly (0); - EXIT END_CASE - CASE (POLYNOM_TOKEN) + CASE (POLYNOMIAL_TOKEN) Object = Parse_Polynom(); - EXIT END_CASE CASE (OVUS_TOKEN) Object = Parse_Ovus(); - EXIT END_CASE CASE (TORUS_TOKEN) Object = Parse_Torus (); - EXIT END_CASE /* Parse lathe primitive. [DB 8/94] */ CASE (LATHE_TOKEN) Object = Parse_Lathe(); - EXIT END_CASE CASE (LEMON_TOKEN) Object = Parse_Lemon(); - EXIT END_CASE /* Parse polygon primitive. [DB 8/94] */ CASE (POLYGON_TOKEN) Object = Parse_Polygon(); - EXIT END_CASE /* Parse prism primitive. [DB 8/94] */ CASE (PRISM_TOKEN) Object = Parse_Prism(); - EXIT END_CASE /* Parse surface of revolution primitive. [DB 8/94] */ CASE (SOR_TOKEN) Object = Parse_Sor(); - EXIT END_CASE /* Parse superellipsoid primitive. [DB 11/94] */ CASE (SUPERELLIPSOID_TOKEN) Object = Parse_Superellipsoid(); - EXIT END_CASE /* Parse triangle mesh primitive. [DB 2/95] */ CASE (MESH_TOKEN) Object = Parse_Mesh(); - EXIT END_CASE /* NK 1998 Parse triangle mesh primitive - syntax version 2. */ CASE (MESH2_TOKEN) Object = Parse_Mesh2(); - EXIT END_CASE /* NK ---- */ CASE (TEXT_TOKEN) Object = Parse_TrueType (); - EXIT END_CASE CASE (OBJECT_ID_TOKEN) Object = Copy_Object(reinterpret_cast(Token.Data)); - EXIT END_CASE CASE (UNION_TOKEN) Object = Parse_CSG (CSG_UNION_TYPE); - EXIT END_CASE CASE (LIGHT_GROUP_TOKEN) Object = Parse_Light_Group (); - EXIT END_CASE CASE (COMPOSITE_TOKEN) VersionWarning(150, "Use union instead of composite."); Object = Parse_CSG (CSG_UNION_TYPE); - EXIT END_CASE CASE (MERGE_TOKEN) Object = Parse_CSG (CSG_MERGE_TYPE); - EXIT END_CASE CASE (INTERSECTION_TOKEN) Object = Parse_CSG (CSG_INTERSECTION_TYPE); - EXIT END_CASE CASE (DIFFERENCE_TOKEN) Object = Parse_CSG (CSG_DIFFERENCE_TYPE+CSG_INTERSECTION_TYPE); - EXIT END_CASE CASE (BICUBIC_PATCH_TOKEN) Object = Parse_Bicubic_Patch (); - EXIT END_CASE CASE (TRIANGLE_TOKEN) Object = Parse_Triangle (); - EXIT END_CASE CASE (SMOOTH_TRIANGLE_TOKEN) Object = Parse_Smooth_Triangle (); - EXIT END_CASE CASE (HEIGHT_FIELD_TOKEN) Object = Parse_HField (); - EXIT END_CASE CASE (BOX_TOKEN) Object = Parse_Box (); - EXIT END_CASE CASE (BLOB_TOKEN) Object = Parse_Blob (); - EXIT END_CASE CASE (LIGHT_SOURCE_TOKEN) Object = Parse_Light_Source (); - EXIT END_CASE CASE (OBJECT_TOKEN) @@ -6778,12 +6730,10 @@ ObjectPtr Parser::Parse_Object () if (!Object) Expectation_Error ("object"); Object = Parse_Object_Mods (reinterpret_cast(Object)); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -6845,7 +6795,7 @@ void Parser::Parse_Default () Default_Texture->Pigment = Local_Pigment; END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Local_Tnormal = Copy_Tnormal((Default_Texture->Tnormal)); Parse_Begin (); Parse_Tnormal (&Local_Tnormal); @@ -7111,18 +7061,15 @@ void Parser::Parse_Global_Settings() Parse_Wavelengths (sceneData->iridWavelengths); END_CASE CASE (CHARSET_TOKEN) - EXPECT + EXPECT_ONE CASE (ASCII_TOKEN) sceneData->stringEncoding = kStringEncoding_ASCII; - EXIT END_CASE CASE (UTF8_TOKEN) sceneData->stringEncoding = kStringEncoding_UTF8; - EXIT END_CASE CASE (SYS_TOKEN) sceneData->stringEncoding = kStringEncoding_System; - EXIT END_CASE OTHERWISE Expectation_Error ("charset type"); @@ -7513,7 +7460,7 @@ void Parser::Parse_Global_Settings() } END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) sceneData->radiositySettings.normal = ((int)Parse_Float() != 0); END_CASE @@ -7759,18 +7706,16 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) if(Object->Clip == Object->Bound) Error ("Cannot add bounds after linking bounds and clips."); - EXPECT + EXPECT_ONE CASE (CLIPPED_BY_TOKEN) if(!Object->Bound.empty()) Error ("Cannot link clips with previous bounds."); Object->Bound = Object->Clip; - EXIT END_CASE OTHERWISE UNGET Parse_Bound_Clip(Object->Bound); - EXIT END_CASE END_EXPECT @@ -7783,12 +7728,11 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) if(Object->Clip == Object->Bound) Error ("Cannot add clips after linking bounds and clips."); - EXPECT + EXPECT_ONE CASE (BOUNDED_BY_TOKEN) if(!Object->Clip.empty()) Error ("Cannot link bounds with previous clips."); Object->Clip = Object->Bound; - EXIT END_CASE OTHERWISE @@ -7804,7 +7748,6 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) (dynamic_cast(Object))->Compute_BBox(Min, Max); } - EXIT END_CASE END_EXPECT @@ -7845,7 +7788,7 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) Object->interior = Local_Material.interior; END_CASE - CASE3 (PIGMENT_TOKEN, TNORMAL_TOKEN, FINISH_TOKEN) + CASE3 (PIGMENT_TOKEN, NORMAL_TOKEN, FINISH_TOKEN) Object->Type |= TEXTURED_OBJECT; if (Object->Texture == NULL) Object->Texture = Copy_Textures(Default_Texture); @@ -7860,7 +7803,7 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) Parse_End (); END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin (); Parse_Tnormal ( &(Object->Texture->Tnormal) ); Parse_End (); @@ -7952,6 +7895,7 @@ ObjectPtr Parser::Parse_Object_Mods (ObjectPtr Object) EXPECT CASE (IMPORTANCE_TOKEN) Object->RadiosityImportance = Parse_Float (); + Object->RadiosityImportanceSet = true; if ( (Object->RadiosityImportance <= 0.0) || (Object->RadiosityImportance > 1.0) ) Error("Radiosity importance must be greater than 0.0 and at most 1.0."); @@ -8091,7 +8035,7 @@ void Parser::Parse_Matrix(MATRIX Matrix) { int i, j; - EXPECT + EXPECT_ONE CASE (LEFT_ANGLE_TOKEN) Matrix[0][0] = Parse_Float(); for (i = 0; i < 4; i++) @@ -8117,7 +8061,6 @@ void Parser::Parse_Matrix(MATRIX Matrix) Matrix[i][i] = 1.0; } } - EXIT END_CASE OTHERWISE @@ -8381,14 +8324,13 @@ int Parser::Parse_Three_UVCoords(Vector2d& UV1, Vector2d& UV2, Vector2d& UV3) { int Return_Value; - EXPECT + EXPECT_ONE CASE(UV_VECTORS_TOKEN) Parse_UV_Vect(UV1); Parse_Comma(); Parse_UV_Vect(UV2); Parse_Comma(); Parse_UV_Vect(UV3); Return_Value = 1; - EXIT END_CASE OTHERWISE @@ -8397,7 +8339,6 @@ int Parser::Parse_Three_UVCoords(Vector2d& UV1, Vector2d& UV2, Vector2d& UV3) UV3[0] = UV3[1] = 0.0; Return_Value = 0; UNGET - EXIT END_CASE END_EXPECT @@ -8436,6 +8377,16 @@ bool Parser::Parse_Comma (void) return true; } +//****************************************************************************** + +bool Parser::Peek_Token (TOKEN tokenId) +{ + Get_Token(); + bool tokenMatches = ((Token.Token_Id == tokenId) || + (Token.Function_Id == tokenId)); + Unget_Token(); + return tokenMatches; +} /***************************************************************************** @@ -8499,7 +8450,7 @@ void Parser::Parse_Coeffs(int order, DBL *Coeffs) { int i; - EXPECT + EXPECT_ONE CASE (LEFT_ANGLE_TOKEN) Coeffs[0] = Parse_Float(); for (i = 1; i < term_counts(order); i++) @@ -8508,7 +8459,6 @@ void Parser::Parse_Coeffs(int order, DBL *Coeffs) Coeffs[i] = Parse_Float(); } GET (RIGHT_ANGLE_TOKEN); - EXIT END_CASE OTHERWISE @@ -8540,18 +8490,16 @@ ObjectPtr Parser::Parse_Object_Id () { ObjectPtr Object; - EXPECT + EXPECT_ONE CASE (OBJECT_ID_TOKEN) Warn_State(OBJECT_ID_TOKEN, OBJECT_TOKEN); Object = Copy_Object(reinterpret_cast(Token.Data)); Object = Parse_Object_Mods (Object); - EXIT END_CASE OTHERWISE Object = NULL; UNGET - EXIT END_CASE END_EXPECT @@ -8608,7 +8556,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) } else { - Local_Index=1; + Local_Index = SYM_TABLE_GLOBAL; } LValue_Ok = true; @@ -8660,9 +8608,16 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) EXPECT_ONE CASE (IDENTIFIER_TOKEN) - POV_PARSER_ASSERT(!Token.is_array_elem); + POV_PARSER_ASSERT(!Token.is_array_elem || Token.is_mixed_array_elem); allow_redefine = true; // should actually be irrelevant downstream, thanks to Previous==IDENTIFIER_TOKEN - Temp_Entry = Add_Symbol (Local_Index,Token.Token_String,IDENTIFIER_TOKEN); + if (Token.is_array_elem || Token.is_dictionary_elem) + { + if (is_local && (Token.context != Table_Index)) + Error ("Cannot use '#local' to assign a non-local array or dictionary element."); + Temp_Entry = Add_Symbol (Token.table, Token.Token_String, IDENTIFIER_TOKEN); + } + else + Temp_Entry = Add_Symbol (Local_Index, Token.Token_String, IDENTIFIER_TOKEN); numberPtr = &(Temp_Entry->Token_Number); dataPtr = &(Temp_Entry->Data); Previous = Token.Token_Id; @@ -8694,17 +8649,17 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) // These are also used in Parse_Directive UNDEF_TOKEN section, Parse_Macro, and and Parse_For_Param_Start, // and all these functions should accept exactly the same identifiers! [trf] - CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) + CASE4 (NORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN) CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN) CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN) CASE4 (DENSITY_MAP_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_ID_TOKEN, UV_ID_TOKEN) CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN) - CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN ) - if (is_local && (Token.Table_Index != Table_Index)) + CASE3 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN, DICTIONARY_ID_TOKEN) + if (is_local && (Token.context != Table_Index)) { - if (Token.is_array_elem) - Error("Cannot use '#local' to assign a non-local array element."); + if (Token.is_array_elem || Token.is_dictionary_elem) + Error ("Cannot use '#local' to assign a non-local array or dictionary element."); allow_redefine = true; // should actually be irrelevant downstream, thanks to Previous==IDENTIFIER_TOKEN Temp_Entry = Add_Symbol (Local_Index,Token.Token_String,IDENTIFIER_TOKEN); numberPtr = &(Temp_Entry->Token_Number); @@ -8713,7 +8668,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) } else { - allow_redefine = !Token.is_array_elem; + allow_redefine = !Token.is_array_elem || Token.is_mixed_array_elem; numberPtr = Token.NumberPtr; dataPtr = Token.DataPtr; Previous = Token.Token_Id; @@ -8733,10 +8688,10 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) { case VECTOR_ID_TOKEN: case FLOAT_ID_TOKEN: - if (is_local && (Token.Table_Index != Table_Index)) + if (is_local && (Token.context != Table_Index)) { - if (Token.is_array_elem) - Error("Cannot use '#local' to assign a non-local array element."); + if (Token.is_array_elem || Token.is_dictionary_elem) + Error("Cannot use '#local' to assign a non-local array or dictionary element."); allow_redefine = true; // should actually be irrelevant downstream, thanks to Previous==IDENTIFIER_TOKEN Temp_Entry = Add_Symbol (Local_Index,Token.Token_String,IDENTIFIER_TOKEN); numberPtr = &(Temp_Entry->Token_Number); @@ -8745,7 +8700,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) } else { - allow_redefine = !Token.is_array_elem; + allow_redefine = !Token.is_array_elem || Token.is_mixed_array_elem; numberPtr = Token.NumberPtr; dataPtr = Token.DataPtr; Previous = Token.Function_Id; @@ -8766,7 +8721,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) // the resulting value. // We do this by assigning the resulting value to a dummy symbol entry. allow_redefine = true; // should actually be irrelevant downstream, thanks to Previous=IDENTIFIER_TOKEN - Temp_Entry = Create_Entry (0, "", DUMMY_SYMBOL_TOKEN); + Temp_Entry = Create_Entry ("", DUMMY_SYMBOL_TOKEN, false); numberPtr = &(Temp_Entry->Token_Number); dataPtr = &(Temp_Entry->Data); optional = true; @@ -8853,14 +8808,14 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) } else if (larrayDeclare) { - SYM_ENTRY *rvalue = Create_Entry (0, "", DUMMY_SYMBOL_TOKEN); + SYM_ENTRY *rvalue = Create_Entry ("", DUMMY_SYMBOL_TOKEN, false); if (!Parse_RValue (IDENTIFIER_TOKEN, &(rvalue->Token_Number), &(rvalue->Data), NULL, false, false, true, true, false, MAX_NUMBER_OF_TABLES) || (rvalue->Token_Number != ARRAY_ID_TOKEN)) Expectation_Error("array RValue"); POV_ARRAY *a = reinterpret_cast(rvalue->Data); - if (lvalues.size() > a->Total) + if (lvalues.size() > a->DataPtrs.size()) Error ("array size mismatch"); - if (a->DataPtrs == NULL) + if (a->DataPtrs.empty()) Error ("cannot assign from uninitialized array"); for (int i = 0; i < lvalues.size(); ++i) @@ -8879,7 +8834,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) *dataPtr = Copy_Identifier(a->DataPtrs[i], a->Type); } - Destroy_Entry (0, rvalue); + Destroy_Entry (rvalue, false); } else { @@ -8944,7 +8899,7 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) for (vector::iterator i = lvalues.begin(); i != lvalues.end(); ++i) { if ((i->symEntry != NULL) && (i->symEntry->Token_Number == DUMMY_SYMBOL_TOKEN)) - Destroy_Entry (0, i->symEntry); + Destroy_Entry (i->symEntry, false); } if ( after_hash ) @@ -8955,6 +8910,18 @@ void Parser::Parse_Declare(bool is_local, bool after_hash) } } +bool Parser::PassParameterByReference (int callingContext) +{ + if (Token.is_dictionary_elem) + { + return true; + } + else + { + return (Token.context <= callingContext); + } +} + bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENTRY *sym, bool ParFlag, bool SemiFlag, bool is_local, bool allow_redefine, bool allowUndefined, int old_table_index) { EXPRESS Local_Express; @@ -8980,21 +8947,21 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT bool callable_identifier; bool had_callable_identifier; SYM_ENTRY* symbol_entry; + SYM_TABLE* symbol_entry_table; - EXPECT - CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) + EXPECT_ONE + CASE4 (NORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN) CASE4 (SLOPE_MAP_ID_TOKEN,NORMAL_MAP_ID_TOKEN,TEXTURE_MAP_ID_TOKEN,ARRAY_ID_TOKEN) CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN,INTERIOR_ID_TOKEN,DENSITY_ID_TOKEN) CASE4 (DENSITY_MAP_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN) - CASE2 (MATERIAL_ID_TOKEN, STRING_ID_TOKEN) - if ((ParFlag) && (Token.Table_Index <= old_table_index)) + CASE3 (MATERIAL_ID_TOKEN, STRING_ID_TOKEN, DICTIONARY_ID_TOKEN) + if ((ParFlag) && PassParameterByReference (old_table_index)) { // pass by reference New_Par = reinterpret_cast(POV_MALLOC(sizeof(POV_PARAM),"parameter")); New_Par->NumberPtr = Token.NumberPtr; New_Par->DataPtr = Token.DataPtr; - New_Par->Table_Index = Token.Table_Index; *NumberPtr = PARAMETER_ID_TOKEN; *DataPtr = reinterpret_cast(New_Par); } @@ -9006,7 +8973,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; } - EXIT END_CASE CASE (IDENTIFIER_TOKEN) @@ -9019,7 +8985,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT { Error("Cannot assign uninitialized identifier."); } - EXIT END_CASE CASE_COLOUR @@ -9036,10 +9001,10 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = COLOUR_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Colour); - EXIT END_CASE } // intentional to allow color dot expressions as macro parameters if #version is 3.5 or higher [trf] + // FALLTHROUGH CASE_VECTOR // It seems very few people understand what is going on here, so let me try to @@ -9078,9 +9043,12 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT if ((Token.Token_Id==FUNCT_ID_TOKEN) || (Token.Token_Id==VECTFUNCT_ID_TOKEN) || (Token.Token_Id==SPLINE_ID_TOKEN) || (Token.Token_Id==UV_ID_TOKEN) || (Token.Token_Id==VECTOR_4D_ID_TOKEN) || (Token.Token_Id==COLOUR_ID_TOKEN)) { - symbol_entry = Find_Symbol(Token.Table_Index, Token.Token_String); + symbol_entry = Find_Symbol (Token.table, Token.Token_String); if (symbol_entry) + { + symbol_entry_table = Token.table; Acquire_Entry_Reference(symbol_entry); + } } else { @@ -9102,7 +9070,7 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT Error("Identifier expected, incomplete function call or spline call found instead."); // only one identifier token has been found so pass it by reference - if (((Temp_Count==-1) || (Temp_Count==TOKEN_OVERFLOW_RESET_COUNT)) && (Token.Table_Index <= old_table_index)) + if (((Temp_Count==-1) || (Temp_Count==TOKEN_OVERFLOW_RESET_COUNT)) && PassParameterByReference (old_table_index)) { // It is important that functions are passed by value and not by reference! [trf] if(!(ParFlag) || (ParFlag && function_identifier)) @@ -9119,7 +9087,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT New_Par = reinterpret_cast(POV_MALLOC(sizeof(POV_PARAM),"parameter")); New_Par->NumberPtr = Token.NumberPtr; New_Par->DataPtr = Token.DataPtr; - New_Par->Table_Index = Token.Table_Index; *NumberPtr = PARAMETER_ID_TOKEN; *DataPtr = reinterpret_cast(New_Par); @@ -9164,11 +9131,10 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT } } if (symbol_entry) - Release_Entry_Reference(Token.Table_Index, symbol_entry); + Release_Entry_Reference (symbol_entry_table, symbol_entry); // allow #declares again Ok_To_Declare = true; - EXIT END_CASE CASE (PIGMENT_TOKEN) @@ -9179,18 +9145,16 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = PIGMENT_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Pigment); - EXIT END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Local_Tnormal = Copy_Tnormal(Default_Texture->Tnormal); Parse_Begin (); Parse_Tnormal (&Local_Tnormal); Parse_End (); - *NumberPtr = TNORMAL_ID_TOKEN; + *NumberPtr = NORMAL_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Tnormal); - EXIT END_CASE CASE (FINISH_TOKEN) @@ -9199,7 +9163,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = FINISH_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Finish); - EXIT END_CASE CASE (CAMERA_TOKEN) @@ -9208,7 +9171,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = CAMERA_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Camera); - EXIT END_CASE CASE (TEXTURE_TOKEN) @@ -9236,7 +9198,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Temp_Texture); Ok_To_Declare = true; - EXIT END_CASE CASE (COLOUR_MAP_TOKEN) @@ -9244,7 +9205,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = COLOUR_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (PIGMENT_MAP_TOKEN) @@ -9252,7 +9212,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = PIGMENT_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (SPLINE_TOKEN) @@ -9263,7 +9222,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = SPLINE_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (DENSITY_MAP_TOKEN) @@ -9271,7 +9229,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = DENSITY_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (SLOPE_MAP_TOKEN) @@ -9279,7 +9236,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = SLOPE_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (TEXTURE_MAP_TOKEN) @@ -9287,7 +9243,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = TEXTURE_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (NORMAL_MAP_TOKEN) @@ -9295,7 +9250,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = NORMAL_MAP_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (RAINBOW_TOKEN) @@ -9303,7 +9257,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = RAINBOW_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (FOG_TOKEN) @@ -9311,7 +9264,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = FOG_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (MEDIA_TOKEN) @@ -9320,7 +9272,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = MEDIA_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (DENSITY_TOKEN) @@ -9331,7 +9282,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = DENSITY_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Density); - EXIT END_CASE CASE (INTERIOR_TOKEN) @@ -9341,7 +9291,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = INTERIOR_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (MATERIAL_TOKEN) @@ -9351,7 +9300,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = MATERIAL_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (SKYSPHERE_TOKEN) @@ -9359,7 +9307,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = SKYSPHERE_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (FUNCTION_TOKEN) @@ -9378,7 +9325,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT Temp_Data = reinterpret_cast(Parse_DeclareFunction(NumberPtr, NULL, is_local)); Test_Redefine(Previous, NumberPtr, *DataPtr, false); *DataPtr = Temp_Data; - EXIT END_CASE CASE (TRANSFORM_TOKEN) @@ -9386,7 +9332,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = TRANSFORM_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Trans); - EXIT END_CASE CASE5 (STRING_LITERAL_TOKEN,CHR_TOKEN,SUBSTR_TOKEN,STR_TOKEN,VSTR_TOKEN) @@ -9396,7 +9341,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = STRING_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT END_CASE CASE (ARRAY_TOKEN) @@ -9404,7 +9348,13 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT *NumberPtr = ARRAY_ID_TOKEN; Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = Temp_Data; - EXIT + END_CASE + + CASE (DICTIONARY_TOKEN) + Temp_Data = reinterpret_cast(Parse_Dictionary_Declare()); + *NumberPtr = DICTIONARY_ID_TOKEN; + Test_Redefine (Previous,NumberPtr,*DataPtr, allow_redefine); + *DataPtr = Temp_Data; END_CASE OTHERWISE @@ -9417,7 +9367,6 @@ bool Parser::Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENT Test_Redefine(Previous,NumberPtr,*DataPtr, allow_redefine); *DataPtr = reinterpret_cast(Local_Object); } - EXIT END_CASE END_EXPECT @@ -9456,7 +9405,7 @@ void Parser::Destroy_Ident_Data(void *Data, int Type) case DENSITY_ID_TOKEN: delete reinterpret_cast(Data); break; - case TNORMAL_ID_TOKEN: + case NORMAL_ID_TOKEN: delete reinterpret_cast(Data); break; case FINISH_ID_TOKEN: @@ -9517,15 +9466,20 @@ void Parser::Destroy_Ident_Data(void *Data, int Type) break; case ARRAY_ID_TOKEN: a = reinterpret_cast(Data); - if(a->DataPtrs != NULL) + if(!a->DataPtrs.empty()) { - for(i=0; iTotal; i++) + for(i=0; iDataPtrs.size(); i++) { - Destroy_Ident_Data(a->DataPtrs[i], a->Type); + if (a->Types.empty()) + Destroy_Ident_Data (a->DataPtrs[i], a->Type); + else + Destroy_Ident_Data (a->DataPtrs[i], a->Types[i]); } - POV_FREE(a->DataPtrs); } - POV_FREE(a); + delete a; + break; + case DICTIONARY_ID_TOKEN: + Destroy_Sym_Table (reinterpret_cast(Data)); break; case PARAMETER_ID_TOKEN: POV_FREE(Data); @@ -9907,8 +9861,14 @@ void Parser::Post_Process (ObjectPtr Object, ObjectPtr Parent) } // promote object-specific radiosity settings to child - if (!Object->RadiosityImportance.isSet()) - Object->RadiosityImportance = Parent->RadiosityImportance(sceneData->radiositySettings.defaultImportance); + if (!Object->RadiosityImportanceSet) + { + if (Parent->RadiosityImportanceSet) + Object->RadiosityImportance = Parent->RadiosityImportance; + else + Object->RadiosityImportance = sceneData->radiositySettings.defaultImportance; + Object->RadiosityImportanceSet = true; + } if(Test_Flag(Parent, PH_PASSTHRU_FLAG)) { @@ -10533,7 +10493,7 @@ void *Parser::Copy_Identifier (void *Data, int Type) case DENSITY_ID_TOKEN: New = reinterpret_cast(Copy_Pigment(reinterpret_cast(Data))); break; - case TNORMAL_ID_TOKEN: + case NORMAL_ID_TOKEN: New = reinterpret_cast(Copy_Tnormal(reinterpret_cast(Data))); break; case FINISH_ID_TOKEN: @@ -10592,16 +10552,30 @@ void *Parser::Copy_Identifier (void *Data, int Type) POV_MEMMOVE(reinterpret_cast(New), reinterpret_cast(Data), len * sizeof(UCS2)); break; case ARRAY_ID_TOKEN: - a=reinterpret_cast(Data); - na=reinterpret_cast(POV_MALLOC(sizeof(POV_ARRAY),"array")); - *na=*a; - na->DataPtrs = reinterpret_cast(POV_MALLOC(sizeof(void *)*(a->Total),"array")); - for (i=0; iTotal; i++) + a = reinterpret_cast(Data); + na = new POV_ARRAY; + na->Dims = a->Dims; + na->Type = a->Type; + na->resizable = a->resizable; + for (i = 0; i < 5; ++i) { - na->DataPtrs[i] = reinterpret_cast(Copy_Identifier (a->DataPtrs[i],a->Type)); + na->Sizes[i] = a->Sizes[i]; + na->Mags[i] = a->Mags[i]; + } + na->DataPtrs.resize(a->DataPtrs.size()); + na->Types = a->Types; + for (i=0; iDataPtrs.size(); i++) + { + if (a->Types.empty()) + na->DataPtrs[i] = reinterpret_cast(Copy_Identifier (a->DataPtrs[i],a->Type)); + else + na->DataPtrs[i] = reinterpret_cast(Copy_Identifier (a->DataPtrs[i], a->Types[i])); } New = reinterpret_cast(na); break; + case DICTIONARY_ID_TOKEN: + New = reinterpret_cast(Copy_Sym_Table (reinterpret_cast(Data))); + break; case FUNCT_ID_TOKEN: case VECTFUNCT_ID_TOKEN: New = reinterpret_cast(fnVMContext->functionvm->CopyFunction((FUNCTION_PTR )Data)); diff --git a/source/parser/parser.h b/source/parser/parser.h index 13c01ea37..a205b70e2 100644 --- a/source/parser/parser.h +++ b/source/parser/parser.h @@ -86,6 +86,12 @@ const int SYM_TABLE_SIZE = 257; typedef struct Sym_Table_Entry SYM_ENTRY; typedef unsigned short SymTableEntryRefCount; +// Special symbol tables +enum { + SYM_TABLE_RESERVED = 0, // reserved words + SYM_TABLE_GLOBAL, // identifiers declared using #declare (or #local in top-level file), #function, #macro, etc. +}; + /// Structure holding information about a symbol struct Sym_Table_Entry { @@ -196,6 +202,10 @@ struct BetaFlags class Parser : public SceneTask { + private: + + struct SYM_TABLE; + public: class DebugTextStreamBuffer : public TextStreamBuffer @@ -221,7 +231,7 @@ class Parser : public SceneTask TOKEN Function_Id; ///< token type ID, in case Token_Id is an identifier ID pov_base::ITextStream::FilePos Token_File_Pos; ///< location of this token in the scene or include file (line number & file position) int Token_Col_No; ///< location of this token in the scene or include file (column) - int Table_Index; + int context; ///< context the token is local to (i.e., table index) char *Token_String; ///< reference to token value (if it is a string literal) or character sequence comprising the token DBL Token_Float; ///< token value (if it is a float literal) int Unget_Token, End_Of_File; @@ -229,7 +239,11 @@ class Parser : public SceneTask void *Data; ///< reference to token value (if it is a non-float identifier) int *NumberPtr; void **DataPtr; - bool is_array_elem; ///< true if token is actually an array element reference + SYM_TABLE *table; ///< table or dictionary the token references an element of + bool is_array_elem : 1; ///< true if token is actually an array element reference + bool is_mixed_array_elem : 1; ///< true if token is actually a mixed-type array element reference + bool is_dictionary_elem : 1; ///< true if token is actually a dictionary element reference + bool freeString : 1; ///< true if Token_String must be freed before being assigned a new value }; struct LValue @@ -266,36 +280,33 @@ class Parser : public SceneTask struct POV_ARRAY { - int Dims, Type, Total; + int Dims, Type; int Sizes[5]; int Mags[5]; - void **DataPtrs; + vector DataPtrs; + vector Types; + bool resizable; }; struct POV_PARAM { int *NumberPtr; void **DataPtr; - int Table_Index; }; struct DATA_FILE { pov_base::ITextStream *In_File; pov_base::OTextStream *Out_File; - bool R_Flag; - }; - - enum IdentifierMode - { - kIdentifierModeUndefined, - kIdentifierModeLocal, - kIdentifierModeGlobal, + bool fopenCompleted : 1; ///< `false` if still busy parsing `#fopen', `true` otherwise. + bool R_Flag : 1; }; // constructor Parser(shared_ptr sd, bool useclock, DBL clock); + ~Parser(); + void Run(); void Stopped(); void Finish(); @@ -309,6 +320,7 @@ class Parser : public SceneTask bool Parse_Begin (bool mandatory = true); void Parse_End (void); bool Parse_Comma (void); + bool Peek_Token (TOKEN tokenId); void Parse_Semi_Colon (bool force_semicolon); void Destroy_Frame (void); void MAError (const char *str, long size); @@ -327,6 +339,7 @@ class Parser : public SceneTask void Parse_Declare (bool is_local, bool after_hash); void Parse_Matrix (MATRIX Matrix); void Destroy_Ident_Data (void *Data, int Type); + bool PassParameterByReference (int oldTableIndex); bool Parse_RValue (int Previous, int *NumberPtr, void **DataPtr, SYM_ENTRY *sym, bool ParFlag, bool SemiFlag, bool is_local, bool allow_redefine, bool allowUndefined, int old_table_index); const char *Get_Token_String (TOKEN Token_Id); void Test_Redefine(TOKEN Previous, TOKEN *NumberPtr, void *Data, bool allow_redefine = true); @@ -368,12 +381,15 @@ class Parser : public SceneTask void pre_init_tokenizer (void); void Initialize_Tokenizer (void); void Terminate_Tokenizer (void); + SYM_ENTRY *Add_Symbol (SYM_TABLE *table, const char *Name,TOKEN Number); SYM_ENTRY *Add_Symbol (int Index,const char *Name,TOKEN Number); POV_ARRAY *Parse_Array_Declare (void); - SYM_ENTRY *Create_Entry (int Index,const char *Name,TOKEN Number); + SYM_TABLE *Parse_Dictionary_Declare(); + SYM_ENTRY *Create_Entry (const char *Name, TOKEN Number, bool copyName); + SYM_ENTRY *Copy_Entry (const SYM_ENTRY *); void Acquire_Entry_Reference (SYM_ENTRY *Entry); - void Release_Entry_Reference (int Index, SYM_ENTRY *Entry); - SYM_ENTRY *Destroy_Entry (int Index,SYM_ENTRY *Entry); + void Release_Entry_Reference (SYM_TABLE *table, SYM_ENTRY *Entry); + SYM_ENTRY *Destroy_Entry (SYM_ENTRY *Entry, bool destroyName); bool Parse_Ifdef_Param (); int Parse_For_Param (char**, DBL*, DBL*); @@ -443,7 +459,7 @@ class Parser : public SceneTask FUNCTION_PTR Parse_Function(void); FUNCTION_PTR Parse_FunctionContent(void); FUNCTION_PTR Parse_FunctionOrContent(void); - void Parse_FunctionOrContentList(GenericScalarFunctionPtr* apFn, unsigned int count); + void Parse_FunctionOrContentList(GenericScalarFunctionPtr* apFn, unsigned int count, bool mandatory = true); FUNCTION_PTR Parse_DeclareFunction(int *token_id, const char *fn_name, bool is_local); // parsestr.h/parsestr.cpp @@ -521,6 +537,7 @@ class Parser : public SceneTask struct SYM_TABLE { SYM_ENTRY *Table[SYM_TABLE_SIZE]; + bool namesAreCopies; }; SYM_TABLE *Tables[MAX_NUMBER_OF_TABLES]; @@ -574,12 +591,11 @@ class Parser : public SceneTask CS_ENTRY *Cond_Stack; int CS_Index; - bool Skipping, Inside_Ifdef, Inside_MacroDef, Parsing_Directive; - IdentifierMode Inside_IdentFn; + bool Skipping, Inside_Ifdef, Inside_MacroDef, Parsing_Directive, parseRawIdentifiers; int Got_EOF; // WARNING: Changes to the use of this variable are very dangerous as it is used in many places assuming certain non-obvious side effects! [trf] - TOKEN Conversion_Util_Table[LAST_TOKEN]; + TOKEN Conversion_Util_Table[TOKEN_COUNT]; // parstxtr.h/parstxtr.cpp TEXTURE *Default_Texture; @@ -677,20 +693,27 @@ class Parser : public SceneTask inline void End_String_Fast (void); bool Read_Float (void); void Read_Symbol (void); - SYM_ENTRY *Find_Symbol (int Index, const char *s); + SYM_ENTRY *Find_Symbol (const SYM_TABLE *table, const char *s, int hash); + SYM_ENTRY *Find_Symbol (const SYM_TABLE *table, const char *s); + SYM_ENTRY *Find_Symbol (int index, const char *s); SYM_ENTRY *Find_Symbol (const char *s); void Skip_Tokens (COND_TYPE cond); void Break (void); int get_hash_value (const char *s); - inline void Write_Token (TOKEN Token_Id, int col); + inline void Write_Token (TOKEN Token_Id, int col, SYM_TABLE *table = NULL); void Destroy_Table (int index); void init_sym_tables (void); void Add_Sym_Table (); + SYM_TABLE *Create_Sym_Table (bool copyNames); + void Destroy_Sym_Table (SYM_TABLE *); + SYM_TABLE *Copy_Sym_Table (const SYM_TABLE *); + void Remove_Symbol (SYM_TABLE *table, const char *Name, bool is_array_elem, void **DataPtr, int ttype); void Remove_Symbol (int Index, const char *Name, bool is_array_elem, void **DataPtr, int ttype); Macro *Parse_Macro(void); void Invoke_Macro(void); void Return_From_Macro(void); + void Add_Entry (SYM_TABLE *table, SYM_ENTRY *Table_Entry); void Add_Entry (int Index,SYM_ENTRY *Table_Entry); void Parse_Initalizer (int Sub, int Base, POV_ARRAY *a); @@ -755,7 +778,7 @@ class Parser : public SceneTask void Parse_Rel_Term (EXPRESS& Express, int *Terms); /// Parses a REL_TERM comparing two strings. - void Parse_Rel_String_Term (const UCS2 *lhs, EXPRESS& Express, int Terms); + DBL Parse_Rel_String_Term (const UCS2 *lhs); /// Parses a LOGICAL_EXPRESSION (including FLOAT) or VECTOR. void Parse_Logical (EXPRESS& Express, int *Terms); diff --git a/source/parser/parser_expressions.cpp b/source/parser/parser_expressions.cpp index bcfc2825b..e512f3c04 100644 --- a/source/parser/parser_expressions.cpp +++ b/source/parser/parser_expressions.cpp @@ -100,7 +100,7 @@ DBL Parser::Parse_Float_Param() { DBL Local; EXPRESS Express; - int Terms = 1; + int Terms; bool old_allow_id = Allow_Identifier_In_Call; Allow_Identifier_In_Call = false; @@ -239,16 +239,14 @@ void Parser::Parse_Trace(Vector3d& Res) GET (LEFT_PAREN_TOKEN); - EXPECT + EXPECT_ONE CASE (OBJECT_ID_TOKEN) Object = reinterpret_cast(Token.Data); - EXIT END_CASE OTHERWISE Object = NULL; UNGET - EXIT END_CASE END_EXPECT @@ -279,7 +277,7 @@ void Parser::Parse_Trace(Vector3d& Res) Local_Normal = Vector3d(0.0, 0.0, 0.0); } - EXPECT + EXPECT_ONE CASE (VECTOR_FUNCT_TOKEN) /* All of these functions return a VECTOR result */ if(Token.Function_Id == VECTOR_ID_TOKEN) @@ -290,12 +288,10 @@ void Parser::Parse_Trace(Vector3d& Res) { UNGET } - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -329,16 +325,14 @@ int Parser::Parse_Inside() GET (LEFT_PAREN_TOKEN); - EXPECT + EXPECT_ONE CASE (OBJECT_ID_TOKEN) Object = reinterpret_cast(Token.Data); - EXIT END_CASE OTHERWISE Object = NULL; UNGET - EXIT END_CASE END_EXPECT @@ -674,6 +668,16 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Ok_To_Declare=true; EXPECT + CASE (PLUS_TOKEN) + END_CASE + + OTHERWISE + UNGET + EXIT + END_CASE + END_EXPECT + + EXPECT_ONE CASE (FLOAT_FUNCT_TOKEN) /* All of these functions return a DBL result */ switch(Token.Function_Id) @@ -937,7 +941,7 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) less_val = Parse_Float(); Parse_Comma(); equal_val = Parse_Float(); - EXPECT + EXPECT_ONE CASE(COMMA_TOKEN) greater_val = Parse_Float(); GET (RIGHT_PAREN_TOKEN); @@ -947,7 +951,6 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Val = equal_val; else Val = greater_val; - EXIT END_CASE OTHERWISE @@ -957,7 +960,6 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Val = less_val; else Val = equal_val; - EXIT END_CASE END_EXPECT break; @@ -1105,9 +1107,9 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) } break; } - for (i=0; i < *Terms; i++) - Express[i]=Val; - EXIT + + *Terms = 1; + Express[0]=Val; END_CASE CASE (VECTOR_FUNCT_TOKEN) @@ -1189,19 +1191,17 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) case MIN_EXTENT_TOKEN: GET (LEFT_PAREN_TOKEN); - EXPECT + EXPECT_ONE CASE (OBJECT_ID_TOKEN) Object = reinterpret_cast(Token.Data); if ( Object ) Vect = Vector3d(Object->BBox.lowerLeft); - EXIT END_CASE OTHERWISE Object = NULL; Vect = Vector3d(0.0,0.0,0.0); UNGET - EXIT END_CASE END_EXPECT @@ -1210,24 +1210,23 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) case MAX_EXTENT_TOKEN: GET (LEFT_PAREN_TOKEN); - EXPECT + EXPECT_ONE CASE (OBJECT_ID_TOKEN) Object = reinterpret_cast(Token.Data); if ( Object ) Vect = Vector3d(Object->BBox.lowerLeft+Object->BBox.size); - EXIT END_CASE // JN2007: Image map dimensions: - CASE3 (DENSITY_ID_TOKEN,PIGMENT_ID_TOKEN,TNORMAL_ID_TOKEN) + CASE4 (DENSITY_ID_TOKEN,NORMAL_ID_TOKEN,PIGMENT_ID_TOKEN,TEXTURE_ID_TOKEN) Pigment = reinterpret_cast(Token.Data); - if(Pigment->Type == BITMAP_PATTERN) + if (dynamic_cast(Pigment->pattern.get())) { - Vect[X] = dynamic_cast(Pigment->pattern.get())->pImage->iwidth; - Vect[Y] = dynamic_cast(Pigment->pattern.get())->pImage->iheight; + Vect[X] = dynamic_cast(Pigment->pattern.get())->pImage->iwidth; + Vect[Y] = dynamic_cast(Pigment->pattern.get())->pImage->iheight; Vect[Z] = 0; } - else if(Pigment->Type == DENSITY_FILE_PATTERN) + else if (dynamic_cast(Pigment->pattern.get())) { Vect[X] = dynamic_cast(Pigment->pattern.get())->densityFile->Data->Sx; Vect[Y] = dynamic_cast(Pigment->pattern.get())->densityFile->Data->Sy; @@ -1237,14 +1236,12 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) { Error("A pigment, normal or density parameter to max_extent must be based on an image or density file."); } - EXIT END_CASE OTHERWISE Object = NULL; Vect = Vector3d(0.0,0.0,0.0); UNGET - EXIT END_CASE END_EXPECT GET (RIGHT_PAREN_TOKEN); @@ -1254,14 +1251,12 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) *Terms = 3; for(i = 0; i < 3; i++) Express[i] = Vect[i]; - EXIT END_CASE CASE (FUNCT_ID_TOKEN) + *Terms = 1; Val = Parse_Function_Call(); - for(i = 0; i < *Terms; i++) - Express[i] = Val; - EXIT + Express[0] = Val; END_CASE CASE (VECTFUNCT_ID_TOKEN) @@ -1269,7 +1264,6 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) for(i = 0; i < *Terms; i++) Express[i] = 0.0; Parse_Vector_Function_Call(Express, Terms); - EXIT END_CASE CASE (SPLINE_ID_TOKEN) @@ -1277,27 +1271,23 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) for(i = 0; i < *Terms; i++) Express[i] = 0.0; Parse_Spline_Call(Express, Terms); - EXIT END_CASE CASE (COLOUR_ID_TOKEN) *Terms=5; (*reinterpret_cast(Token.Data)).Get(Express, *Terms); - EXIT END_CASE CASE (UV_ID_TOKEN) *Terms=2; for (i=0; i<2; i++) Express[i]=(DBL)( (*reinterpret_cast(Token.Data))[i] ); - EXIT END_CASE CASE (VECTOR_4D_ID_TOKEN) *Terms=4; for (i=0; i<4; i++) Express[i]=(DBL)( (reinterpret_cast(Token.Data))[i] ); - EXIT END_CASE CASE (T_TOKEN) @@ -1306,24 +1296,18 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Express[1]=0.0; Express[2]=0.0; Express[3]=1.0; - EXIT END_CASE CASE (U_TOKEN) *Terms=2; Express[0]=1.0; Express[1]=0.0; - EXIT END_CASE CASE (V_TOKEN) *Terms=2; Express[0]=0.0; Express[1]=1.0; - EXIT - END_CASE - - CASE (PLUS_TOKEN) END_CASE CASE (DASH_TOKEN) @@ -1333,7 +1317,6 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Ok_To_Declare=true; for (i=0; i<*Terms; i++) Express[i]=-Express[i]; - EXIT END_CASE CASE (EXCLAMATION_TOKEN) @@ -1343,13 +1326,11 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Ok_To_Declare=true; for (i=0; i<*Terms; i++) Express[i] = ftrue(Express[i])?0.0:1.0; - EXIT END_CASE CASE (LEFT_PAREN_TOKEN) Parse_Express(Express,Terms); GET(RIGHT_PAREN_TOKEN); - EXIT END_CASE /* This case parses a 2, 3, 4, or 5 term vector. First parse 2 terms. @@ -1361,17 +1342,17 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Express[Y] = Parse_Float(); Parse_Comma(); *Terms=2; - EXPECT + EXPECT_ONE CASE_EXPRESS - /* If a 3th float is found, parse it. */ + /* If a 3rd float is found, parse it. */ Express[2] = Parse_Float(); Parse_Comma(); *Terms=3; - EXPECT + EXPECT_ONE CASE_EXPRESS /* If a 4th float is found, parse it. */ Express[3] = Parse_Float(); Parse_Comma(); *Terms=4; - EXPECT + EXPECT_ONE CASE_EXPRESS /* If a 5th float is found, parse it. */ Express[4] = Parse_Float(); @@ -1381,31 +1362,24 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) OTHERWISE /* Only 4 found. */ UNGET - GET (RIGHT_ANGLE_TOKEN) - EXIT END_CASE END_EXPECT - EXIT END_CASE OTHERWISE /* Only 3 found. */ UNGET - GET (RIGHT_ANGLE_TOKEN) - EXIT END_CASE END_EXPECT - EXIT END_CASE OTHERWISE /* Only 2 found. */ UNGET - GET (RIGHT_ANGLE_TOKEN) - EXIT END_CASE END_EXPECT - EXIT + + GET (RIGHT_ANGLE_TOKEN) END_CASE OTHERWISE @@ -1416,9 +1390,9 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Ok_To_Declare=Old_Ok; /* Parse VECTOR.x or COLOR.red type things */ - EXPECT + EXPECT_ONE CASE(PERIOD_TOKEN) - EXPECT + EXPECT_ONE CASE (VECTOR_FUNCT_TOKEN) switch(Token.Function_Id) { @@ -1437,7 +1411,6 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) default: Expectation_Error ("x, y, or z"); } - EXIT END_CASE CASE (COLOUR_KEY_TOKEN) @@ -1471,22 +1444,18 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) default: Expectation_Error ("red, green, blue, filter, transmit, gray or vector component"); } - EXIT END_CASE CASE(U_TOKEN) i=U; - EXIT END_CASE CASE(V_TOKEN) i=V; - EXIT END_CASE CASE(T_TOKEN) i=T; - EXIT END_CASE OTHERWISE @@ -1498,12 +1467,10 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) Error("Bad operands for period operator."); *Terms=1; Express[0]=Express[i]; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT } @@ -1528,11 +1495,13 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms) * ******************************************************************************/ -/* If first operand of a 2-operand function had more terms than the second, - then the parsing of the 2nd operand would have automatically promoted it. - But if 2nd operand has more terms then we must go back promote the 1st - operand before combining them Promote_Express does it. If Old_Terms=1 - then set all terms to Express[0]. Otherwise pad extra terms with 0.0. +/* Promote_Express promotes Express to the requested number of terms. If + *Old_Terms==1, then it sets all terms to Express[0]. Otherwise, it pads + extra terms with 0.0. + + To maximize the consistency of results, DO NOT promote until it is actually + required. This is to ensure, as much as possible, that the same expression + will produce the same results regardless of the context. */ void Parser::Promote_Express(EXPRESS& Express,int *Old_Terms,int New_Terms) @@ -1591,8 +1560,6 @@ void Parser::Parse_Num_Term (EXPRESS& Express,int *Terms) Parse_Num_Factor(Express,Terms); - Local_Terms=*Terms; - EXPECT CASE (STAR_TOKEN) Parse_Num_Factor(Local_Express,&Local_Terms); @@ -1664,8 +1631,6 @@ void Parser::Parse_Rel_Factor (EXPRESS& Express,int *Terms) Parse_Num_Term(Express,Terms); - Local_Terms=*Terms; - EXPECT CASE (PLUS_TOKEN) Parse_Num_Term(Local_Express,&Local_Terms); @@ -1724,9 +1689,9 @@ void Parser::Parse_Rel_Factor (EXPRESS& Express,int *Terms) * ******************************************************************************/ -void Parser::Parse_Rel_String_Term (const UCS2 *lhs, EXPRESS& Express, int Terms) +DBL Parser::Parse_Rel_String_Term (const UCS2 *lhs) { - int Val, i; + int Val; UCS2 *rhs = NULL; EXPECT_ONE @@ -1735,8 +1700,7 @@ void Parser::Parse_Rel_String_Term (const UCS2 *lhs, EXPRESS& Express, int Terms Val = UCS2_strcmp(lhs, rhs); POV_FREE(rhs); - for(i=0;i= 0); + return (DBL)(Val >= 0); END_CASE CASE (RIGHT_ANGLE_TOKEN) @@ -1780,8 +1740,7 @@ void Parser::Parse_Rel_String_Term (const UCS2 *lhs, EXPRESS& Express, int Terms Val = UCS2_strcmp(lhs, rhs); POV_FREE(rhs); - for(i=0;i 0); + return (DBL)(Val > 0); END_CASE OTHERWISE @@ -1821,7 +1780,8 @@ void Parser::Parse_Rel_Term (EXPRESS& Express,int *Terms) UCS2 *Local_String = Parse_String(false, false); if(Local_String != NULL) { - Parse_Rel_String_Term(Local_String, Express, *Terms); + *Terms = 1; + Express[0] = Parse_Rel_String_Term(Local_String); POV_FREE(Local_String); Ok_To_Declare = old_Ok_To_Declare; return; @@ -1830,9 +1790,10 @@ void Parser::Parse_Rel_Term (EXPRESS& Express,int *Terms) Parse_Rel_Factor(Express,Terms); - Local_Terms=*Terms; - EXPECT + + // TODO REVIEW - I guess we want to issue a warning if the loop is run multiple times. + CASE (LEFT_ANGLE_TOKEN) Parse_Rel_Factor(Local_Express,&Local_Terms); Promote_Express(Express,Terms,Local_Terms); @@ -1917,8 +1878,6 @@ void Parser::Parse_Logical (EXPRESS& Express,int *Terms) Parse_Rel_Term(Express,Terms); - Local_Terms=*Terms; - EXPECT CASE (AMPERSAND_TOKEN) Parse_Rel_Term(Local_Express,&Local_Terms); @@ -1970,47 +1929,32 @@ void Parser::Parse_Express (EXPRESS& Express,int *Terms) EXPRESS *Chosen; int Local_Terms1, Local_Terms2; - Local_Terms1 = 1; - Parse_Logical(Express,&Local_Terms1); - EXPECT + EXPECT_ONE CASE (QUESTION_TOKEN) if (Local_Terms1 != 1) Error("Conditional must evaluate to a float."); - Local_Terms1 = Local_Terms2 = *Terms; Parse_Express(Local_Express1,&Local_Terms1); GET(COLON_TOKEN); Parse_Express(Local_Express2,&Local_Terms2); if (ftrue(Express[0])) { - Chosen = reinterpret_cast(&Local_Express1); + Chosen = &Local_Express1; *Terms = Local_Terms1; } else { - Chosen = reinterpret_cast(&Local_Express2); + Chosen = &Local_Express2; *Terms = Local_Terms2; } POV_MEMCPY(Express,Chosen,sizeof(EXPRESS)); - EXIT END_CASE OTHERWISE - /* Not a (c)?a:b expression. Since Express was parsed with - Local_Terms1=1 then we may have to promote this. Suppose - Terms=3 but Local_Terms1=1. If this had been a (c)?a:b - then a float is ok but since it is not a condition then - it must be promoted to Terms=3. Note that the parameters - below look wrong but they are not. - */ - Promote_Express (Express,&Local_Terms1,*Terms); - /* On the other hand, Local_Terms1 may be bigger than Terms. - If so, Express already is promoted and Terms must reflect that. - */ + /* Not a (c)?a:b expression. */ *Terms=Local_Terms1; UNGET - EXIT END_CASE END_EXPECT @@ -2043,8 +1987,6 @@ DBL Parser::Parse_Float () bool old_allow_id = Allow_Identifier_In_Call; Allow_Identifier_In_Call = false; - Terms=1; - if (sceneData->EffectiveLanguageVersion() < 150) Parse_Num_Factor(Express,&Terms); else @@ -2142,16 +2084,14 @@ DBL Parser::Allow_Float (DBL defval) { DBL retval; - EXPECT + EXPECT_ONE CASE_EXPRESS retval = Parse_Float(); - EXIT END_CASE OTHERWISE UNGET retval = defval; - EXIT END_CASE END_EXPECT @@ -2181,17 +2121,15 @@ int Parser::Allow_Vector (Vector3d& Vect) { int retval; - EXPECT + EXPECT_ONE CASE_EXPRESS Parse_Vector(Vect); retval = true; - EXIT END_CASE OTHERWISE UNGET retval = false; - EXIT END_CASE END_EXPECT @@ -2232,8 +2170,6 @@ void Parser::Parse_Vector (Vector3d& Vector) Express[Terms] = 0.0; } - Terms=3; - if (sceneData->EffectiveLanguageVersion() < 150) Parse_Num_Factor(Express,&Terms); else @@ -2242,6 +2178,8 @@ void Parser::Parse_Vector (Vector3d& Vector) if (Terms>3) Error ("Vector expected but color expression found."); + Promote_Express(Express,&Terms,3); + for(Terms=0;Terms<3;Terms++) Vector[Terms]=Express[Terms]; @@ -2271,7 +2209,6 @@ void Parser::Parse_Vector4D (VECTOR_4D Vector) { EXPRESS Express; int Terms; - int Dim = 4; bool old_allow_id = Allow_Identifier_In_Call; Allow_Identifier_In_Call = false; @@ -2282,17 +2219,17 @@ void Parser::Parse_Vector4D (VECTOR_4D Vector) Express[Terms] = 0.0; } - Terms=Dim; - if (sceneData->EffectiveLanguageVersion() < 150) Parse_Num_Factor(Express,&Terms); else Parse_Rel_Factor(Express,&Terms); - if (Terms>Dim) + if (Terms>4) Error ("Vector expected but color expression found."); - for(Terms=0;TermsEffectiveLanguageVersion() < 150) Parse_Num_Factor(Express,&Terms); else @@ -2343,6 +2278,8 @@ void Parser::Parse_UV_Vect (Vector2d& UV_Vect) if (Terms>2) Error ("UV_Vector expected but vector or color expression found."); + Promote_Express(Express,&Terms,2); + for(Terms=0;Terms<2;Terms++) UV_Vect[Terms]=Express[Terms]; @@ -2384,8 +2321,6 @@ int Parser::Parse_Unknown_Vector(EXPRESS& Express, bool allow_identifier, bool * Express[Terms] = 0.0; } - Terms=1; - if (sceneData->EffectiveLanguageVersion() < 150) Parse_Num_Factor(Express,&Terms); else @@ -2462,7 +2397,7 @@ void Parser::Parse_Scale_Vector (Vector3d& Vector) void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) { EXPRESS Express; - int Terms; + int Terms, tgtTerms; bool old_allow_id = Allow_Identifier_In_Call, sawFloatOrFloatFnct; Allow_Identifier_In_Call = false; @@ -2518,8 +2453,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) } else { - Terms=3; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,3); if (Terms != 3) Warning("Suspicious expression after rgb."); colour.Set(Express, Terms); @@ -2534,8 +2469,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) } else { - Terms=4; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,4); if (Terms != 4) Warning("Suspicious expression after rgbf."); colour.Set(Express, Terms); @@ -2552,8 +2487,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) } else { - Terms=4; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,4); if (Terms != 4) Warning("Suspicious expression after rgbt."); colour.Set(Express, Terms); @@ -2572,8 +2507,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) } else { - Terms=5; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,5); if (Terms != 5) Warning("Suspicious expression after rgbft."); colour.Set(Express, Terms); @@ -2612,8 +2547,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) { if (!sceneData->workingGammaToSRGB) Error("Cannot parse sRGB colors before assumed_gamma has been set."); - Terms=3; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,3); if (Terms != 3) Warning("Suspicious expression after srgb."); colour.Set(Express, Terms); @@ -2631,8 +2566,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) { if (!sceneData->workingGammaToSRGB) Error("Cannot parse sRGB colors before assumed_gamma has been set."); - Terms=4; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,4); if (Terms != 4) Warning("Suspicious expression after srgbf."); colour.Set(Express, Terms); @@ -2652,8 +2587,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) { if (!sceneData->workingGammaToSRGB) Error("Cannot parse sRGB colors before assumed_gamma has been set."); - Terms=4; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,4); if (Terms != 4) Warning("Suspicious expression after srgbt."); colour.Set(Express, Terms); @@ -2675,8 +2610,8 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) { if (!sceneData->workingGammaToSRGB) Error("Cannot parse sRGB colors before assumed_gamma has been set."); - Terms=5; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,5); if (Terms != 5) Warning("Suspicious expression after srgbft."); colour.Set(Express, Terms); @@ -2698,10 +2633,11 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) else { if (expectFT) - Terms = 5; + tgtTerms = 5; else - Terms = 3; + tgtTerms = 3; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,tgtTerms); colour.Set(Express, Terms); if (!expectFT && ((colour.filter() != 0) || (colour.transm() != 0))) Warning("Expected pure RGB color expression, unexpected filter and transmit components will have no effect."); @@ -2718,19 +2654,19 @@ void Parser::Parse_Colour (RGBFTColour& colour, bool expectFT) else { // Note: Setting up for potential warning on single value float promote to - // five value color vector. Under the Parse_Express call there is code which - // promotes any single float to the full 'Terms' value on the call. This - // usually results in filter and trasmit values >0, which cause shadow artifacts - // back to at least version 3.6.1. + // five value color vector. Any single float will be promoted to the full + // 'tgtTerms' value. This usually results in filter and trasmit values >0, + // which caused shadow artifacts back to at least version 3.6.1. if ((Token.Token_Id==FLOAT_FUNCT_TOKEN) || (Token.Token_Id==FUNCT_ID_TOKEN)) sawFloatOrFloatFnct = true; else sawFloatOrFloatFnct = false; if (expectFT) - Terms = 5; + tgtTerms = 5; else - Terms = 3; + tgtTerms = 3; Parse_Express(Express,&Terms); + Promote_Express(Express,&Terms,tgtTerms); if (expectFT && (Terms != 5)) Error("Color expression expected but float or vector expression found."); else if (!expectFT && ((Terms < 3) || Terms > 5)) @@ -2781,7 +2717,7 @@ void Parser::Parse_Wavelengths (MathColour& colour) Parse_Colour (tempColour, false); colour = ToMathColour(tempColour.rgb()); #else - #error TODO! + #error "TODO!" #endif } @@ -2805,7 +2741,7 @@ void Parser::Parse_Wavelengths (MathColour& colour) * * Chris Young 11/94 * -* DESCRIPTION : +* DESCRIPTION * * CHANGES * @@ -3177,7 +3113,7 @@ shared_ptr Parser::Parse_Blend_List (int Count, ColourBlendMapConstPtr De case kBlendMapType_Normal: EXPECT - CASE(TNORMAL_TOKEN) + CASE(NORMAL_TOKEN) Parse_Begin (); Parse_BlendListData(Blend_Type,tempList[i].Vals); Parse_End (); @@ -3259,17 +3195,15 @@ shared_ptr Parser::Parse_Blend_List New; POV_BLEND_MAP_ASSERT(Blend_Type == kBlendMapType_Pigment); - EXPECT + EXPECT_ONE CASE(PIGMENT_TOKEN) UNGET New = Parse_Blend_List (Count, Def_Map, kBlendMapType_Pigment); - EXIT END_CASE OTHERWISE UNGET New = Parse_Blend_List (Count, Def_Map, kBlendMapType_Colour); - EXIT END_CASE END_EXPECT return New; @@ -3408,8 +3342,8 @@ template TextureBlendMapPtr Parser::Parse_Item_Into_Blend_List * * POV-Ray Team * -* DESCRIPTION : This seperate routine parses color_maps only. It -* cannot be used for pigment_maps because it accomidates +* DESCRIPTION : This separate routine parses color_maps only. It +* cannot be used for pigment_maps because it accommodates * the old double entry color maps from vers 1.0 * * CHANGES @@ -3457,12 +3391,11 @@ ColourBlendMapPtr Parser::Parse_Colour_Map () CASE (LEFT_SQUARE_TOKEN) Temp_Ent.value = Parse_Float(); Parse_Comma(); - EXPECT + EXPECT_ONE /* After [ must be a float. If 2nd thing found is another float then this is an old style color_map. */ CASE_FLOAT - Terms=1; Parse_Express(Express,&Terms); if (Terms==1) { @@ -3484,19 +3417,16 @@ ColourBlendMapPtr Parser::Parse_Colour_Map () } else Error("Illegal expression syntax in color_map."); - EXIT END_CASE CASE_COLOUR Parse_Colour (Temp_Ent.Vals); tempList.push_back(Temp_Ent); - EXIT END_CASE OTHERWISE Expectation_Error("color"); UNGET - EXIT END_CASE END_EXPECT @@ -3605,7 +3535,7 @@ TextureBlendMapPtr Parser::Parse_Colour_Map () * * Wolfgang Ortmann * -* DESCRIPTION : This seperate routine parses pure splines only. Splines in +* DESCRIPTION : This separate routine parses pure splines only. Splines in * lathe objects and SOR are similar but not identical * * CHANGES @@ -3620,6 +3550,7 @@ GenericSpline *Parser::Parse_Spline() { GenericSpline * Old = NULL; GenericSpline * New = NULL; + bool keepOld = false; int i = 0; EXPRESS Express; int Terms, MaxTerms; @@ -3630,17 +3561,16 @@ GenericSpline *Parser::Parse_Spline() MaxTerms = 2; /*Check for spline identifier*/ - EXPECT + EXPECT_ONE CASE(SPLINE_ID_TOKEN) Old = reinterpret_cast(Token.Data); i = Old->SplineEntries.size(); MaxTerms = Old->Terms; - EXIT + keepOld = true; END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -3651,7 +3581,10 @@ GenericSpline *Parser::Parse_Spline() New = new LinearSpline(*Old); else New = new LinearSpline(); + if (Old && !keepOld) + delete Old; Old = New; + keepOld = false; END_CASE CASE(QUADRATIC_SPLINE_TOKEN) @@ -3659,7 +3592,10 @@ GenericSpline *Parser::Parse_Spline() New = new QuadraticSpline(*Old); else New = new QuadraticSpline(); + if (Old && !keepOld) + delete Old; Old = New; + keepOld = false; END_CASE CASE(CUBIC_SPLINE_TOKEN) @@ -3667,7 +3603,10 @@ GenericSpline *Parser::Parse_Spline() New = new CatmullRomSpline(*Old); else New = new CatmullRomSpline(); + if (Old && !keepOld) + delete Old; Old = New; + keepOld = false; END_CASE CASE(NATURAL_SPLINE_TOKEN) @@ -3675,7 +3614,10 @@ GenericSpline *Parser::Parse_Spline() New = new NaturalSpline(*Old); else New = new NaturalSpline(); + if (Old && !keepOld) + delete Old; Old = New; + keepOld = false; END_CASE OTHERWISE @@ -3698,8 +3640,8 @@ GenericSpline *Parser::Parse_Spline() par = Parse_Float(); Parse_Comma(); - Terms = 2; Parse_Express(Express, &Terms); + Promote_Express(Express,&Terms,2); if(Terms > 5) Error("Too many components in vector!\n"); MaxTerms = max(MaxTerms, Terms); @@ -3948,7 +3890,7 @@ DBL Parser::Parse_Signed_Float(void) CASE (DASH_TOKEN) Sign=-1.0; Get_Token(); - /* Deliberate fall through with no END_CASE */ + // FALLTHROUGH CASE (FLOAT_FUNCT_TOKEN) if (Token.Function_Id==FLOAT_TOKEN) { diff --git a/source/parser/parser_functions.cpp b/source/parser/parser_functions.cpp index 28921daba..d6f89b973 100644 --- a/source/parser/parser_functions.cpp +++ b/source/parser/parser_functions.cpp @@ -110,10 +110,10 @@ const ExprParserTableEntry expr_parser_table[] = { 35, RIGHT_PAREN_TOKEN, &Parser::expr_ret, -1, OP_NONE }, // 12 { 35, RIGHT_CURLY_TOKEN, &Parser::expr_ret, -1, OP_NONE }, // 13 { 35, COMMA_TOKEN, &Parser::expr_ret, -1, OP_NONE }, // 14 - { 35, LAST_TOKEN, &Parser::expr_err, -1, OP_NONE }, // 15 + { 35, TOKEN_COUNT, &Parser::expr_err, -1, OP_NONE }, // 15 // vector/color member access { 45, PERIOD_TOKEN, &Parser::expr_grow, 60, OP_DOT }, // 16 - { 45, LAST_TOKEN, &Parser::expr_err, -1, OP_NONE }, // 17 + { 45, TOKEN_COUNT, &Parser::expr_err, -1, OP_NONE }, // 17 // unary plus, unary minus, (logical not - disabled) { 40, PLUS_TOKEN, &Parser::expr_noop, 50, OP_NONE }, // 18 { 40, DASH_TOKEN, &Parser::expr_grow, 50, OP_NEG }, // 19 @@ -124,10 +124,10 @@ const ExprParserTableEntry expr_parser_table[] = { 50, FUNCT_ID_TOKEN, &Parser::expr_call, 5, OP_CALL }, // 23 { 50, VECTFUNCT_ID_TOKEN,&Parser::expr_call, 45, OP_CALL }, // 24 { 50, LEFT_PAREN_TOKEN, &Parser::expr_new, 55, OP_FIRST }, // 25 - { 50, LAST_TOKEN, &Parser::expr_err, -1, OP_NONE }, // 26 + { 50, TOKEN_COUNT, &Parser::expr_err, -1, OP_NONE }, // 26 // (expression) { 55, RIGHT_PAREN_TOKEN, &Parser::expr_noop, 5, OP_NONE }, // 27 - { 55, LAST_TOKEN, &Parser::expr_err, -1, OP_NONE }, // 28 + { 55, TOKEN_COUNT, &Parser::expr_err, -1, OP_NONE }, // 28 // vector/color members { 60, FLOAT_ID_TOKEN, &Parser::expr_put, 5, OP_MEMBER }, // 29 { 60, T_TOKEN, &Parser::expr_put, 5, OP_MEMBER }, // 30 @@ -137,7 +137,7 @@ const ExprParserTableEntry expr_parser_table[] = { 60, FILTER_TOKEN, &Parser::expr_put, 5, OP_MEMBER }, // 34 { 60, TRANSMIT_TOKEN, &Parser::expr_put, 5, OP_MEMBER }, // 35 { 60, GRAY_TOKEN, &Parser::expr_put, 5, OP_MEMBER }, // 36 - { 60, LAST_TOKEN, &Parser::expr_err, -1, OP_NONE } // 37 + { 60, TOKEN_COUNT, &Parser::expr_err, -1, OP_NONE } // 37 }; // parse_expr has to start with first unary operator [trf] @@ -332,7 +332,7 @@ ExprNode *Parser::parse_expr() for(i = start_index; ; i++) { if((expr_parser_table[i].token == token) || - (expr_parser_table[i].token == LAST_TOKEN)) + (expr_parser_table[i].token == TOKEN_COUNT)) break; } diff --git a/source/parser/parser_functions_utilities.cpp b/source/parser/parser_functions_utilities.cpp index 906895aa1..07ea98695 100644 --- a/source/parser/parser_functions_utilities.cpp +++ b/source/parser/parser_functions_utilities.cpp @@ -163,13 +163,18 @@ FUNCTION_PTR Parser::Parse_FunctionOrContent(void) } -void Parser::Parse_FunctionOrContentList(GenericScalarFunctionPtr* apFn, unsigned int count) +void Parser::Parse_FunctionOrContentList(GenericScalarFunctionPtr* apFn, unsigned int count, bool mandatory) { for (unsigned int i = 0; i < count; ++i) { - if (i > 0) - Parse_Comma(); + if (!mandatory && (Peek_Token(RIGHT_CURLY_TOKEN) || Parse_Comma())) + { + apFn[i] = NULL; + continue; + } apFn[i] = new FunctionVM::CustomFunction(fnVMContext->functionvm, Parse_FunctionOrContent()); + if (i < count-1) + Parse_Comma(); } } @@ -308,14 +313,18 @@ FUNCTION_PTR Parser::Parse_DeclareFunction(int *token_id, const char *fn_name, b } else if(Token.Token_Id == STRING_LITERAL_TOKEN) { +#if (DEBUG_FLOATFUNCTION == 1) f.SetFlag(2, Token.Token_String); +#endif Get_Token(); if(Token.Token_Id == COMMA_TOKEN) { Get_Token(); if(Token.Token_Id != STRING_LITERAL_TOKEN) Expectation_Error("valid function expression"); +#if (DEBUG_FLOATFUNCTION == 1) f.SetFlag(1, Token.Token_String); +#endif } else { diff --git a/source/parser/parser_materials.cpp b/source/parser/parser_materials.cpp index f56da8429..43690212f 100644 --- a/source/parser/parser_materials.cpp +++ b/source/parser/parser_materials.cpp @@ -212,7 +212,7 @@ ImageData *Parser::Parse_Image(int Legal, bool GammaCorrect) END_EXPECT } - EXPECT + EXPECT_ONE CASE (FUNCTION_TOKEN) image->width = (SNGL)int(Parse_Float() + 0.5); Parse_Comma(); @@ -225,86 +225,72 @@ ImageData *Parser::Parse_Image(int Legal, bool GammaCorrect) fnPtr = Parse_DeclareFunction(&token_id, NULL, false); Make_Pattern_Image(image, fnPtr, token_id); - EXIT END_CASE CASE (IFF_TOKEN) filetype = IFF_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (GIF_TOKEN) filetype = GIF_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (POT_TOKEN) filetype = POT_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (SYS_TOKEN) filetype = SYS_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (TGA_TOKEN) filetype = TGA_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (PNG_TOKEN) filetype = PNG_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (PGM_TOKEN) filetype = PGM_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (PPM_TOKEN) filetype = PPM_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (JPEG_TOKEN) filetype = JPEG_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (TIFF_TOKEN) mExperimentalFlags.tiff = true; filetype = TIFF_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (BMP_TOKEN) filetype = BMP_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (EXR_TOKEN) filetype = EXR_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE (HDR_TOKEN) filetype = HDR_FILE; Name = Parse_C_String(true); - EXIT END_CASE CASE5 (STRING_LITERAL_TOKEN,CHR_TOKEN,SUBSTR_TOKEN,STR_TOKEN,VSTR_TOKEN) @@ -359,7 +345,6 @@ ImageData *Parser::Parse_Image(int Legal, bool GammaCorrect) } } } - EXIT END_CASE OTHERWISE @@ -513,24 +498,20 @@ ImageData *Parser::Parse_Image(int Legal, bool GammaCorrect) SimpleGammaCurvePtr Parser::Parse_Gamma (void) { SimpleGammaCurvePtr gamma; - EXPECT + EXPECT_ONE CASE (COLOUR_KEY_TOKEN) if (Token.Function_Id != SRGB_TOKEN) { UNGET - EXIT END_CASE } gamma = SRGBGammaCurve::Get(); - EXIT END_CASE CASE (BT709_TOKEN) gamma = BT709GammaCurve::Get(); - EXIT END_CASE CASE (BT2020_TOKEN) gamma = BT2020GammaCurve::Get(); - EXIT END_CASE OTHERWISE { @@ -542,7 +523,6 @@ SimpleGammaCurvePtr Parser::Parse_Gamma (void) // (we're not warning about below-1.0-values in non-gamma-corrected scenes, as it is likely to make sense there) PossibleError("Suspicious value %g specified for gamma. Did you mean %g?\n", value, 1.0/value); gamma = PowerLawGammaCurve::GetByDecodingGamma(value); - EXIT } END_CASE END_EXPECT @@ -649,7 +629,7 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) switch(Token.Function_Id) { case FILTER_TOKEN: - EXPECT + EXPECT_ONE CASE (ALL_TOKEN) { DBL filter; @@ -672,7 +652,6 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) } } } - EXIT END_CASE OTHERWISE @@ -696,7 +675,6 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t); image->data->SetRGBFTIndexedValue(reg, r, g, b, Parse_Float(), t); } - EXIT END_CASE END_EXPECT @@ -704,7 +682,7 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) break; case TRANSMIT_TOKEN: - EXPECT + EXPECT_ONE CASE (ALL_TOKEN) { DBL transmit; @@ -727,7 +705,6 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) } } } - EXIT END_CASE OTHERWISE @@ -751,7 +728,6 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t); image->data->SetRGBFTIndexedValue(reg, r, g, b, f, Parse_Float()); } - EXIT END_CASE END_EXPECT @@ -771,7 +747,7 @@ void Parser::Parse_Image_Map (PIGMENT *Pigment) END_CASE END_EXPECT - dynamic_cast(Pigment->pattern.get())->pImage=image; + dynamic_cast(Pigment->pattern.get())->pImage=image; Parse_End(); } @@ -853,7 +829,7 @@ void Parser::Parse_Bump_Map (TNORMAL *Tnormal) END_CASE END_EXPECT - dynamic_cast(Tnormal->pattern.get())->pImage = image; + dynamic_cast(Tnormal->pattern.get())->pImage = image; Parse_End(); } @@ -935,7 +911,7 @@ void Parser::Parse_Image_Pattern (TPATTERN *TPattern) END_CASE END_EXPECT - dynamic_cast(TPattern->pattern.get())->pImage = image; + dynamic_cast(TPattern->pattern.get())->pImage = image; Parse_End(); } @@ -962,16 +938,14 @@ void Parser::Parse_Image_Pattern (TPATTERN *TPattern) void Parser::Parse_Pigment (PIGMENT **Pigment_Ptr) { - EXPECT /* Look for [pigment_id] */ + EXPECT_ONE /* Look for [pigment_id] */ CASE (PIGMENT_ID_TOKEN) Destroy_Pigment(*Pigment_Ptr); *Pigment_Ptr = Copy_Pigment (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT /* End pigment_id */ @@ -1022,29 +996,23 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) ContinuousPattern* pContinuousPattern; DBL low, high; - if (Old_Type==BITMAP_PATTERN) - { - Old_Image = dynamic_cast(New->pattern.get())->pImage; - } + if (dynamic_cast(New->pattern.get())) + Old_Image = dynamic_cast(New->pattern.get())->pImage; - if (Old_Type==DENSITY_FILE_PATTERN) - { + if (dynamic_cast(New->pattern.get())) Old_Density_File = dynamic_cast(New->pattern.get())->densityFile; - } - EXPECT + EXPECT_ONE CASE (AGATE_TOKEN) - New->Type = AGATE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new AgatePattern()); Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); dynamic_cast(New->pattern.get())->agateTurbScale = 1.0; // TODO this is a job for a constructor - EXIT END_CASE CASE (BOZO_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BozoPattern()); - EXIT END_CASE CASE (FUNCTION_TOKEN) @@ -1052,7 +1020,16 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) New->pattern = PatternPtr(new FunctionPattern()); dynamic_cast(New->pattern.get())->pFn = new FunctionVM::CustomFunction( dynamic_cast(sceneData->functionContextFactory), Parse_Function()); - EXIT + END_CASE + + CASE (USER_DEFINED_TOKEN) + if ((TPat_Type != kBlendMapType_Pigment) && (TPat_Type != kBlendMapType_Density)) + Only_In("user_defined", "pigment or density"); + New->Type = COLOUR_PATTERN; + New->pattern = PatternPtr(new ColourFunctionPattern()); + Parse_Begin(); + Parse_FunctionOrContentList (dynamic_cast(New->pattern.get())->pFn, 5, false); + Parse_End(); END_CASE CASE(PIGMENT_PATTERN_TOKEN) @@ -1063,41 +1040,36 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_Pigment(&(dynamic_cast(New->pattern.get())->pPigment)); Post_Pigment(dynamic_cast(New->pattern.get())->pPigment); Parse_End(); - EXIT END_CASE CASE (GRANITE_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new GranitePattern()); - EXIT END_CASE CASE (LEOPARD_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new LeopardPattern()); - EXIT END_CASE CASE (MARBLE_TOKEN) - New->Type = MARBLE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new MarblePattern()); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (MANDEL_TOKEN) - New->Type = MANDEL_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern()); dynamic_cast(New->pattern.get())->maxIterations = Parse_Int_With_Minimum(1, "fractal iterations limit"); dynamic_cast(New->pattern.get())->interiorType = DEFAULT_FRACTAL_INTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorType = DEFAULT_FRACTAL_EXTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; - EXIT END_CASE CASE (JULIA_TOKEN) - New->Type = JULIA_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new JuliaPattern()); Parse_UV_Vect(dynamic_cast(New->pattern.get())->juliaCoord); Parse_Comma(); @@ -1106,39 +1078,33 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->exteriorType = DEFAULT_FRACTAL_EXTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; - EXIT END_CASE CASE (MAGNET_TOKEN) - New->Type = NO_PATTERN; + New->Type = GENERIC_PATTERN; i = (int)Parse_Float(); - EXPECT + EXPECT_ONE CASE (MANDEL_TOKEN) switch(i) { case 1: - New->Type = MAGNET1M_PATTERN; New->pattern = PatternPtr(new Magnet1MPattern()); break; case 2: - New->Type = MAGNET2M_PATTERN; New->pattern = PatternPtr(new Magnet2MPattern()); break; default: Error("Invalid magnet-mandel pattern type found. Valid types are 1 and 2."); break; } - EXIT END_CASE CASE (JULIA_TOKEN) switch(i) { case 1: - New->Type = MAGNET1J_PATTERN; New->pattern = PatternPtr(new Magnet1JPattern()); break; case 2: - New->Type = MAGNET2J_PATTERN; New->pattern = PatternPtr(new Magnet2JPattern()); break; default: @@ -1147,7 +1113,6 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) } Parse_UV_Vect(dynamic_cast(New->pattern.get())->juliaCoord); Parse_Comma(); - EXIT END_CASE OTHERWISE Error("Invalid magnet pattern found. Valid types are 'mandel' and 'julia'."); @@ -1160,13 +1125,11 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; dynamic_cast(New->pattern.get())->maxIterations = Parse_Int_With_Minimum(1, "fractal iterations limit"); - EXIT END_CASE CASE (ONION_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new OnionPattern()); - EXIT END_CASE CASE (SPIRAL1_TOKEN) @@ -1174,7 +1137,6 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) New->pattern = PatternPtr(new Spiral1Pattern()); dynamic_cast(New->pattern.get())->arms = (short)Parse_Float (); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (SPIRAL2_TOKEN) @@ -1182,20 +1144,17 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) New->pattern = PatternPtr(new Spiral2Pattern()); dynamic_cast(New->pattern.get())->arms = (short)Parse_Float (); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (SPOTTED_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new SpottedPattern()); - EXIT END_CASE CASE (WOOD_TOKEN) - New->Type = WOOD_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new WoodPattern()); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (GRADIENT_TOKEN) @@ -1204,17 +1163,15 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_Vector (Local_Vector); Local_Vector.normalize(); dynamic_cast(New->pattern.get())->gradient = Local_Vector; - EXIT END_CASE CASE (RADIAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new RadialPattern()); - EXIT END_CASE CASE (CRACKLE_TOKEN) - New->Type = CRACKLE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CracklePattern()); dynamic_cast(New->pattern.get())->crackleIsSolid = 0; dynamic_cast(New->pattern.get())->crackleForm[X] = -1; @@ -1222,7 +1179,6 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->crackleForm[Z] = 0; dynamic_cast(New->pattern.get())->crackleMetric = 2; dynamic_cast(New->pattern.get())->crackleOffset = 0; - EXIT END_CASE CASE_COLOUR @@ -1233,23 +1189,20 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) New->Type = PLAIN_PATTERN; New->pattern = PatternPtr(new PlainPattern()); Parse_Colour ((reinterpret_cast(New))->colour); - EXIT END_CASE CASE (UV_MAPPING_TOKEN) New->Type = UV_MAP_PATTERN; New->pattern = PatternPtr(new PlainPattern()); New->Blend_Map = Parse_Item_Into_Blend_List(TPat_Type); - EXIT END_CASE CASE (CHECKER_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CheckerPattern()); New->Blend_Map = Parse_Blend_List(2,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE CASE (OBJECT_TOKEN) @@ -1259,25 +1212,23 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_Bound_Clip(tempObjects, false); if(tempObjects.size() != 1) Error ("object or object identifier expected."); - New->Type = OBJECT_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new ObjectPattern()); dynamic_cast(New->pattern.get())->pObject = tempObjects[0]; New->Blend_Map = Parse_Blend_List(2,New->pattern->GetDefaultBlendMap(),TPat_Type); Parse_End(); - EXIT } END_CASE CASE (CELLS_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CellsPattern()); - EXIT END_CASE CASE (BRICK_TOKEN) - if (New->Type!=BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) { - New->Type = BRICK_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BrickPattern()); dynamic_cast(New->pattern.get())->brickSize = Vector3d(8.0,3.0,4.5); dynamic_cast(New->pattern.get())->mortar=0.5-EPSILON*2.0; @@ -1285,44 +1236,39 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) New->Blend_Map = Parse_Blend_List(2,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE CASE (HEXAGON_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new HexagonPattern()); New->Blend_Map = Parse_Blend_List(3,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE CASE (SQUARE_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new SquarePattern()); New->Blend_Map = Parse_Blend_List(4,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE CASE (TRIANGULAR_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new TriangularPattern()); New->Blend_Map = Parse_Blend_List(6,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE // JN2007: Cubic pattern CASE (CUBIC_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CubicPattern()); New->Blend_Map = Parse_Blend_List(6,New->pattern->GetDefaultBlendMap(),TPat_Type); if (TPat_Type == kBlendMapType_Normal) (reinterpret_cast(New))->Delta = 0.02; - EXIT END_CASE CASE (IMAGE_MAP_TOKEN) @@ -1331,16 +1277,12 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Only_In("image_map","pigment"); } - if (Old_Type==BITMAP_PATTERN) - { + if (Old_Image) Destroy_Image(Old_Image); - } - New->Type = BITMAP_PATTERN; - New->pattern = PatternPtr(new ImagePattern()); - dynamic_cast(New->pattern.get())->waveFrequency = 0.0; + New->Type = IMAGE_MAP_PATTERN; + New->pattern = PatternPtr(new ColourImagePattern()); Parse_Image_Map (reinterpret_cast(New)); - EXIT END_CASE CASE (BUMP_MAP_TOKEN) @@ -1349,46 +1291,38 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Only_In("bump_map","normal"); } - if (Old_Type==BITMAP_PATTERN) - { + if (Old_Image) Destroy_Image(Old_Image); - } New->Type = BITMAP_PATTERN; New->pattern = PatternPtr(new ImagePattern()); dynamic_cast(New->pattern.get())->waveFrequency = 0.0; Parse_Bump_Map (reinterpret_cast(New)); - EXIT END_CASE CASE (WAVES_TOKEN) New->Type = WAVES_PATTERN; New->pattern = PatternPtr(new WavesPattern()); - EXIT END_CASE CASE (RIPPLES_TOKEN) New->Type = RIPPLES_PATTERN; New->pattern = PatternPtr(new RipplesPattern()); - EXIT END_CASE CASE (WRINKLES_TOKEN) New->Type = WRINKLES_PATTERN; New->pattern = PatternPtr(new WrinklesPattern()); - EXIT END_CASE CASE (BUMPS_TOKEN) New->Type = BUMPS_PATTERN; New->pattern = PatternPtr(new BumpsPattern()); - EXIT END_CASE CASE (DENTS_TOKEN) New->Type = DENTS_PATTERN; New->pattern = PatternPtr(new DentsPattern()); - EXIT END_CASE CASE (QUILTED_TOKEN) @@ -1397,7 +1331,6 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->Control0 = 1.0; dynamic_cast(New->pattern.get())->Control1 = 1.0; dynamic_cast(New->pattern.get())->waveFrequency = 0.0; - EXIT END_CASE CASE (FACETS_TOKEN) @@ -1410,58 +1343,47 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->facetsSize = 0.1; dynamic_cast(New->pattern.get())->facetsCoords = 0; dynamic_cast(New->pattern.get())->facetsMetric = 2; - EXIT END_CASE CASE (AVERAGE_TOKEN) New->Type = AVERAGE_PATTERN; - New->pattern = PatternPtr(new PlainPattern()); - EXIT + New->pattern = PatternPtr(new AveragePattern()); END_CASE CASE (IMAGE_PATTERN_TOKEN) - if ((Old_Type==BITMAP_PATTERN) || (Old_Type==IMAGE_PATTERN)) - { + if (Old_Image) Destroy_Image(Old_Image); - } - New->Type = IMAGE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new ImagePattern()); dynamic_cast(New->pattern.get())->waveFrequency = 0.0; Parse_Image_Pattern (New); - EXIT END_CASE CASE (PLANAR_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new PlanarPattern()); - EXIT END_CASE CASE (BOXED_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BoxedPattern()); - EXIT END_CASE CASE (SPHERICAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new SphericalPattern()); - EXIT END_CASE CASE (CYLINDRICAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CylindricalPattern()); - EXIT END_CASE CASE (DENSITY_FILE_TOKEN) - if (Old_Type==DENSITY_FILE_PATTERN) - { + if (Old_Density_File) Destroy_Density_File(Old_Density_File); - } - New->Type = DENSITY_FILE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new DensityFilePattern()); dynamic_cast(New->pattern.get())->densityFile = Create_Density_File(); GET(DF3_TOKEN); @@ -1472,7 +1394,6 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Error("Cannot read media density file."); Read_Density_File(dfile, dynamic_cast(New->pattern.get())->densityFile); } - EXIT END_CASE CASE (SLOPE_TOKEN) @@ -1487,11 +1408,10 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->altitudeModWidth = 0.0; dynamic_cast(New->pattern.get())->pointAt = false; - EXPECT + EXPECT_ONE /* simple syntax */ CASE_EXPRESS Parse_Vector (dynamic_cast(New->pattern.get())->slopeDirection); - EXIT END_CASE /* new syntax */ @@ -1502,11 +1422,9 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) EXPECT_ONE CASE(POINT_AT_TOKEN) dynamic_cast(New->pattern.get())->pointAt = true; - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -1570,12 +1488,10 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_End(); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -1620,17 +1536,15 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) else if (dynamic_cast(New->pattern.get())->altitudeDirection[i] == -1.0) { dynamic_cast(New->pattern.get())->altitudeAxis = -(i+1); break; } } } - EXIT END_CASE CASE (AOI_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new AOIPattern()); - EXIT END_CASE CASE (PAVEMENT_TOKEN) - New->Type = PAVEMENT_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new PavementPattern()); dynamic_cast(New->pattern.get())->Side = 3; dynamic_cast(New->pattern.get())->Tile = 1; @@ -1638,14 +1552,12 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) dynamic_cast(New->pattern.get())->Exterior = 0; dynamic_cast(New->pattern.get())->Interior = 0; dynamic_cast(New->pattern.get())->Form = 0; - EXIT END_CASE CASE (TILING_TOKEN) - New->Type = TILING_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new TilingPattern()); dynamic_cast(New->pattern.get())->tilingType = (unsigned char)Parse_Float(); - EXIT END_CASE CASE (POTENTIAL_TOKEN) @@ -1672,26 +1584,19 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) EXIT END_CASE END_EXPECT - - EXIT } END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT /* Concludes pattern_body */ - if ((Old_Type==BITMAP_PATTERN) && (New->Type!=BITMAP_PATTERN)) - { + if (Old_Image && !dynamic_cast(New->pattern.get())) Destroy_Image(Old_Image); - } - if ((Old_Type==DENSITY_FILE_PATTERN) && (New->Type!=DENSITY_FILE_PATTERN)) - { + if (Old_Density_File && !dynamic_cast(New->pattern.get())) Destroy_Density_File(Old_Density_File); - } if (TPat_Type == kBlendMapType_Normal) { @@ -1709,29 +1614,18 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) END_CASE CASE (SOLID_TOKEN) - if (New->Type != CRACKLE_PATTERN ) - { + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->crackleIsSolid = 1; + else Only_In("solid", "crackle"); - } - dynamic_cast(New->pattern.get())->crackleIsSolid = 1; END_CASE CASE (EXTERIOR_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN) || - (New->Type == MAGNET1M_PATTERN) || (New->Type == MAGNET2M_PATTERN) || - (New->Type == MAGNET1J_PATTERN) || (New->Type == MAGNET2J_PATTERN) || - (New->Type == PAVEMENT_PATTERN))) - { - Only_In("exterior", "mandel, julia, magnet or pavement"); - } - else if (New->Type == PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->Exterior = (unsigned char)Parse_Float(); } - else + else if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->exteriorType = (int)Parse_Float(); if((dynamic_cast(New->pattern.get())->exteriorType < 0) || (dynamic_cast(New->pattern.get())->exteriorType > 8)) @@ -1739,24 +1633,18 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_Comma(); dynamic_cast(New->pattern.get())->exteriorFactor = Parse_Float(); } - END_CASE - - CASE (INTERIOR_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN) || - (New->Type == MAGNET1M_PATTERN) || (New->Type == MAGNET2M_PATTERN) || - (New->Type == MAGNET1J_PATTERN) || (New->Type == MAGNET2J_PATTERN) || - (New->Type == PAVEMENT_PATTERN))) + else { Only_In("exterior", "mandel, julia, magnet or pavement"); } - else if (New->Type == PAVEMENT_PATTERN) + END_CASE + + CASE (INTERIOR_TOKEN) + if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->Interior = (unsigned char)Parse_Float(); } - else + else if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->interiorType = (int)Parse_Float(); if((dynamic_cast(New->pattern.get())->interiorType < 0) || (dynamic_cast(New->pattern.get())->interiorType > 6)) @@ -1764,45 +1652,35 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Parse_Comma(); dynamic_cast(New->pattern.get())->interiorFactor = Parse_Float(); } - END_CASE - - CASE (EXPONENT_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN))) + else { - Only_In("exponent", "mandel or julia"); + Only_In("exterior", "mandel, julia, magnet or pavement"); } + END_CASE - if((New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN)) + CASE (EXPONENT_TOKEN) + if (dynamic_cast(New->pattern.get())) { i = (int)Parse_Float(); switch(i) { case 2: - New->Type = JULIA_PATTERN; New->pattern = PatternPtr(new JuliaPattern(*dynamic_cast(New->pattern.get()))); break; case 3: - New->Type = JULIA3_PATTERN; New->pattern = PatternPtr(new Julia3Pattern(*dynamic_cast(New->pattern.get()))); break; case 4: - New->Type = JULIA4_PATTERN; New->pattern = PatternPtr(new Julia4Pattern(*dynamic_cast(New->pattern.get()))); break; default: if((i > 4) && (i <= kFractalMaxExponent)) { - New->Type = JULIAX_PATTERN; New->pattern = PatternPtr(new JuliaXPattern(*dynamic_cast(New->pattern.get()))); dynamic_cast(New->pattern.get())->fractalExponent = i; } else { - New->Type = JULIA_PATTERN; New->pattern = PatternPtr(new JuliaPattern(*dynamic_cast(New->pattern.get()))); Warning("Invalid julia pattern exponent found. Supported exponents are 2 to %i.\n" "Using default exponent 2.", kFractalMaxExponent); @@ -1810,34 +1688,28 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) break; } } - else if((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN)) + else if (dynamic_cast(New->pattern.get())) { i = (int)Parse_Float(); switch(i) { case 2: - New->Type = MANDEL_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern(*dynamic_cast(New->pattern.get()))); break; case 3: - New->Type = MANDEL3_PATTERN; New->pattern = PatternPtr(new Mandel3Pattern(*dynamic_cast(New->pattern.get()))); break; case 4: - New->Type = MANDEL4_PATTERN; New->pattern = PatternPtr(new Mandel4Pattern(*dynamic_cast(New->pattern.get()))); break; default: if((i > 4) && (i <= kFractalMaxExponent)) { - New->Type = MANDELX_PATTERN; New->pattern = PatternPtr(new MandelXPattern(*dynamic_cast(New->pattern.get()))); dynamic_cast(New->pattern.get())->fractalExponent = i; } else { - New->Type = MANDEL_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern(*dynamic_cast(New->pattern.get()))); Warning("Invalid mandel pattern exponent found. Supported exponents are 2 to %i.\n" "Using default exponent 2.", kFractalMaxExponent); @@ -1845,29 +1717,33 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) break; } } + else + { + Only_In("exponent", "mandel or julia"); + } END_CASE CASE (COORDS_TOKEN) - if (New->Type == FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->facetsCoords = Parse_Float(); else Only_In("coords", "facets"); END_CASE CASE (SIZE_TOKEN) - if (New->Type == FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->facetsSize = Parse_Float(); else Only_In("size", "facets"); END_CASE CASE (METRIC_TOKEN) - if (New->Type == FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) { Parse_Vector(Local_Vector); dynamic_cast(New->pattern.get())->facetsMetric = Local_Vector[X]; } - else if ( New->Type == CRACKLE_PATTERN ) + else if (dynamic_cast(New->pattern.get())) { // Vector for backwards compatibility // the only component used was always X. @@ -1879,16 +1755,16 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) END_CASE CASE (FORM_TOKEN) - if (New->Type == CRACKLE_PATTERN) - Parse_Vector( dynamic_cast(New->pattern.get())->crackleForm ); - else if (New->Type == PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + Parse_Vector(dynamic_cast(New->pattern.get())->crackleForm); + else if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->Form = ((unsigned char)Parse_Float()); else Only_In("form", "crackle or pavement"); END_CASE CASE (OFFSET_TOKEN) - if (New->Type == CRACKLE_PATTERN ) + if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->crackleOffset = Parse_Float(); else Only_In("offset", "crackle"); @@ -1904,15 +1780,8 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("color_map","pigment"); } - if (New->Type == BRICK_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == AVERAGE_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) - { + if (New->Type == AVERAGE_PATTERN || !New->pattern->CanMap()) Error("Cannot use color_map with this pattern type."); - } New->Blend_Map = Parse_Colour_Map (); END_CASE @@ -1921,11 +1790,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("pigment_map","pigment"); } - if (New->Type == BRICK_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) + if (!New->pattern->CanMap()) Not_With ("pigment_map","this pigment type"); New->Blend_Map = Parse_Blend_Map (kBlendMapType_Pigment,New->Type); END_CASE @@ -1935,11 +1800,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("density_map","density"); } - if (New->Type == BRICK_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) + if (!New->pattern->CanMap()) Not_With ("density_map","this density type"); New->Blend_Map = Parse_Blend_Map (kBlendMapType_Density,New->Type); END_CASE @@ -1949,12 +1810,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("slope_map","normal"); } - if (New->Type == BRICK_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == AVERAGE_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) + if (New->Type == AVERAGE_PATTERN || !New->pattern->CanMap()) Not_With ("slope_map","this normal type"); New->Blend_Map = Parse_Blend_Map (kBlendMapType_Slope,New->Type); END_CASE @@ -1964,12 +1820,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("normal_map","normal"); } - if (New->Type == BRICK_PATTERN || - New->Type == FACETS_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) + if (New->Type == FACETS_PATTERN || !New->pattern->CanMap()) Not_With ("normal_map","this normal type"); New->Blend_Map = Parse_Blend_Map (kBlendMapType_Normal,New->Type); END_CASE @@ -1979,11 +1830,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) { Only_In("texture_map","texture"); } - if (New->Type == BRICK_PATTERN || - New->Type == GENERIC_INTEGER_PATTERN || - New->Type == PLAIN_PATTERN || - New->Type == OBJECT_PATTERN || - New->Type == BITMAP_PATTERN) + if (!New->pattern->CanMap()) Not_With ("texture_map","this pattern type"); New->Blend_Map = Parse_Blend_Map (kBlendMapType_Texture,New->Type); END_CASE @@ -1997,14 +1844,14 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) END_CASE CASE (CONTROL0_TOKEN) - if (New->Type == QUILTED_PATTERN) + if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->Control0 = Parse_Float (); else Not_With ("control0","this pattern"); END_CASE CASE (CONTROL1_TOKEN) - if (New->Type == QUILTED_PATTERN) + if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->Control1 = Parse_Float (); else Not_With ("control1","this pattern"); @@ -2035,7 +1882,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) pContinuousPattern->waveFrequency = Parse_Float(); else { - Warning("frequrency has no effect on discrete patterns"); + Warning("frequency has no effect on discrete patterns"); Parse_Float(); } END_CASE @@ -2122,46 +1969,53 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) END_CASE CASE (AGATE_TURB_TOKEN) - if (New->Type != AGATE_PATTERN) + if (dynamic_cast(New->pattern.get())) + { + dynamic_cast(New->pattern.get())->agateTurbScale = Parse_Float(); + Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); /* agate needs Octaves, Lambda etc. */ + } + else Not_With ("agate_turb","non-agate"); - dynamic_cast(New->pattern.get())->agateTurbScale = Parse_Float(); - Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); /* agate needs Octaves, Lambda etc. */ END_CASE CASE (BRICK_SIZE_TOKEN) - if (New->Type != BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) Not_With ("brick_size","non-brick"); Parse_Vector(dynamic_cast(New->pattern.get())->brickSize); END_CASE CASE (MORTAR_TOKEN) - if (New->Type != BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) Not_With ("mortar","non-brick"); dynamic_cast(New->pattern.get())->mortar = Parse_Float()-EPSILON*2.0; END_CASE CASE (INTERPOLATE_TOKEN) - if (New->Type != DENSITY_FILE_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->densityFile->Interpolation = (int)Parse_Float(); + else Not_With ("interpolate","non-density_file"); - dynamic_cast(New->pattern.get())->densityFile->Interpolation = (int)Parse_Float(); END_CASE CASE (NUMBER_OF_SIDES_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Side=(unsigned char)Parse_Float(); + else Only_In("number_of_sides","pavement"); - dynamic_cast(New->pattern.get())->Side=(unsigned char)Parse_Float(); END_CASE CASE (NUMBER_OF_TILES_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Tile=(unsigned char)Parse_Float(); + else Only_In("number_of_tiles","pavement"); - dynamic_cast(New->pattern.get())->Tile=(unsigned char)Parse_Float(); END_CASE CASE (PATTERN_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Number=(unsigned char)Parse_Float(); + else Only_In("pattern","pavement"); - dynamic_cast(New->pattern.get())->Number=(unsigned char)Parse_Float(); END_CASE CASE (WARP_TOKEN) @@ -2225,7 +2079,7 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) Error("Patterned texture must have texture_map."); } - if (New->Type == PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) { const int valid6[]={1,1,3,7,22}; const int valid4[]={1,1,2,5,12,35}; @@ -2275,10 +2129,10 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) } } - - if ((New->Type==TILING_PATTERN) && ((dynamic_cast(New->pattern.get())->tilingType < 1) || (dynamic_cast(New->pattern.get())->tilingType > 27))) + else if (dynamic_cast(New->pattern.get())) { - Error("Tiling number must be between 1 and 27."); + if ((dynamic_cast(New->pattern.get())->tilingType < 1) || (dynamic_cast(New->pattern.get())->tilingType > 27)) + Error("Tiling number must be between 1 and 27."); } } @@ -2306,16 +2160,14 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type) void Parser::Parse_Tnormal (TNORMAL **Tnormal_Ptr) { - EXPECT /* Look for [tnormal_id] */ - CASE (TNORMAL_ID_TOKEN) + EXPECT_ONE /* Look for [tnormal_id] */ + CASE (NORMAL_ID_TOKEN) Destroy_Tnormal(*Tnormal_Ptr); *Tnormal_Ptr = Copy_Tnormal (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT /* End [tnormal_id] */ @@ -2371,17 +2223,15 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) Parse_Begin (); - EXPECT /* Look for zero or one finish_id */ + EXPECT_ONE /* Look for zero or one finish_id */ CASE (FINISH_ID_TOKEN) if (*Finish_Ptr) delete *Finish_Ptr; *Finish_Ptr = Copy_Finish (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT /* End finish_id */ @@ -2429,14 +2279,13 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) CASE (REFLECTION_TOKEN) { bool found_second_color = false; - EXPECT + EXPECT_ONE /* old syntax */ CASE_EXPRESS Parse_Colour(New->Reflection_Max); New->Reflection_Min = New->Reflection_Max; New->Reflection_Falloff = 1; New->Reflection_Fresnel = false; - EXIT END_CASE /* new syntax */ @@ -2449,18 +2298,16 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) Parse_Comma(); /* look for a second color */ - EXPECT + EXPECT_ONE CASE_EXPRESS Parse_Colour(New->Reflection_Max); found_second_color = true; - EXIT END_CASE OTHERWISE UNGET /* by default, use reflection min = reflection max */ New->Reflection_Max = New->Reflection_Min; - EXIT END_CASE END_EXPECT @@ -2497,12 +2344,10 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) END_EXPECT Parse_End(); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -2555,15 +2400,13 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) CASE (METALLIC_TOKEN) New->Metallic = 1.0; - EXPECT + EXPECT_ONE CASE_FLOAT New->Metallic = Parse_Float(); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT END_CASE @@ -2632,6 +2475,10 @@ void Parser::Parse_Finish (FINISH **Finish_Ptr) Parse_End(); END_CASE + CASE (USE_ALPHA_TOKEN) + New->AlphaKnockout = ((int) Allow_Float(1.0) != 0); + END_CASE + OTHERWISE UNGET EXIT @@ -2733,17 +2580,15 @@ TEXTURE *Parser::Parse_Texture () Modified_Pnf = false; - EXPECT /* First allow a texture identifier */ + EXPECT_ONE /* First allow a texture identifier */ CASE (TEXTURE_ID_TOKEN) Texture = Copy_Textures(reinterpret_cast(Token.Data)); Modified_Pnf = true; - EXIT END_CASE OTHERWISE UNGET Texture = Copy_Textures (Default_Texture); - EXIT END_CASE END_EXPECT @@ -2766,8 +2611,8 @@ TEXTURE *Parser::Parse_Texture () Modified_Pnf = true; END_CASE - CASE (TNORMAL_ID_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + CASE (NORMAL_ID_TOKEN) + Warn_State(Token.Token_Id, NORMAL_TOKEN); Destroy_Tnormal(Texture->Tnormal); Texture->Tnormal = Copy_Tnormal (reinterpret_cast(Token.Data)); Modified_Pnf = true; @@ -2800,7 +2645,7 @@ TEXTURE *Parser::Parse_Texture () Modified_Pnf = true; END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin (); Parse_Tnormal ( &(Texture->Tnormal) ); Parse_End (); @@ -2876,21 +2721,19 @@ TEXTURE *Parser::Parse_Texture () no p, n or f. Nor any texture identifier. Its probably a patterned texture_map texture. */ - EXPECT + EXPECT_ONE CASE (TILES_TOKEN) Destroy_Textures (Texture); Texture = Parse_Tiles(); if (Texture->Blend_Map->Blend_Map_Entries[1].Vals == NULL) Error("First texture missing from tiles"); Parse_Texture_Transform(Texture); - EXIT END_CASE CASE (MATERIAL_MAP_TOKEN) Destroy_Textures (Texture); Texture = Parse_Material_Map (); Parse_Texture_Transform(Texture); - EXIT END_CASE OTHERWISE @@ -2911,7 +2754,6 @@ TEXTURE *Parser::Parse_Texture () Destroy_Textures(Texture); Texture = Copy_Textures (Default_Texture); } - EXIT END_CASE END_EXPECT } @@ -2955,7 +2797,7 @@ TEXTURE *Parser::Parse_Tiles() Texture->Pigment = NULL; Texture->Tnormal = NULL; Texture->Finish = NULL; - Texture->Type = GENERIC_INTEGER_PATTERN; + Texture->Type = GENERIC_PATTERN; Texture->pattern = PatternPtr(new CheckerPattern()); Texture->Blend_Map = Create_Blend_Map (kBlendMapType_Texture); @@ -3042,34 +2884,36 @@ TEXTURE *Parser::Parse_Material_Map() Texture->Type = BITMAP_PATTERN; Texture->pattern = PatternPtr(new ImagePattern()); - dynamic_cast(Texture->pattern.get())->pImage = Parse_Image(MATERIAL_FILE); - dynamic_cast(Texture->pattern.get())->pImage->Use = USE_NONE; // was false [trf] + ImageDataPtr& pImage = dynamic_cast(Texture->pattern.get())->pImage; + + pImage = Parse_Image(MATERIAL_FILE); + pImage->Use = USE_NONE; // was false [trf] EXPECT CASE (ONCE_TOKEN) - dynamic_cast(Texture->pattern.get())->pImage->Once_Flag=true; + pImage->Once_Flag=true; END_CASE CASE (INTERPOLATE_TOKEN) - dynamic_cast(Texture->pattern.get())->pImage->Interpolation_Type=(int)Parse_Float(); + pImage->Interpolation_Type=(int)Parse_Float(); END_CASE CASE (MAP_TYPE_TOKEN) - dynamic_cast(Texture->pattern.get())->pImage->Map_Type = (int) Parse_Float (); + pImage->Map_Type = (int) Parse_Float (); END_CASE CASE (REPEAT_TOKEN) Parse_UV_Vect (Repeat); if ((Repeat[0]<=0.0) || (Repeat[1]<=0.0)) Error("Zero or Negative Image Repeat Vector."); - dynamic_cast(Texture->pattern.get())->pImage->width = (DBL)dynamic_cast(Texture->pattern.get())->pImage->iwidth * Repeat[0]; - dynamic_cast(Texture->pattern.get())->pImage->height = (DBL)dynamic_cast(Texture->pattern.get())->pImage->iheight * Repeat[1]; + pImage->width = (DBL)pImage->iwidth * Repeat[0]; + pImage->height = (DBL)pImage->iheight * Repeat[1]; END_CASE CASE (OFFSET_TOKEN) - Parse_UV_Vect (dynamic_cast(Texture->pattern.get())->pImage->Offset); - dynamic_cast(Texture->pattern.get())->pImage->Offset[U] *= (DBL)-dynamic_cast(Texture->pattern.get())->pImage->iwidth; - dynamic_cast(Texture->pattern.get())->pImage->Offset[V] *= (DBL)-dynamic_cast(Texture->pattern.get())->pImage->iheight; + Parse_UV_Vect (pImage->Offset); + pImage->Offset[U] *= -(DBL)pImage->iwidth; + pImage->Offset[V] *= -(DBL)pImage->iheight; END_CASE OTHERWISE @@ -3135,28 +2979,24 @@ TEXTURE *Parser::Parse_Vers1_Texture () FINISH *Finish; ContinuousPattern* pContinuousPattern; - EXPECT /* Look for texture_body */ + EXPECT_ONE /* Look for texture_body */ CASE (TILES_TOKEN) Texture = Parse_Tiles(); if (Texture->Blend_Map->Blend_Map_Entries[1].Vals == NULL) Error("First texture missing from tiles"); - EXIT END_CASE CASE (MATERIAL_MAP_TOKEN) Texture = Parse_Material_Map (); - EXIT END_CASE CASE (TEXTURE_ID_TOKEN) Texture = Copy_Textures(reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET Texture = Copy_Textures (Default_Texture); - EXIT END_CASE END_EXPECT @@ -3169,7 +3009,7 @@ TEXTURE *Parser::Parse_Vers1_Texture () Texture->Pigment = Copy_Pigment (reinterpret_cast(Token.Data)); END_CASE - CASE (TNORMAL_ID_TOKEN) + CASE (NORMAL_ID_TOKEN) Destroy_Tnormal(Texture->Tnormal); Texture->Tnormal = Copy_Tnormal (reinterpret_cast(Token.Data)); END_CASE @@ -3197,7 +3037,7 @@ TEXTURE *Parser::Parse_Vers1_Texture () Parse_End (); END_CASE - CASE (TNORMAL_TOKEN) + CASE (NORMAL_TOKEN) Parse_Begin (); Parse_Tnormal ( &(Texture->Tnormal) ); Parse_End (); @@ -3213,7 +3053,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. ***********************************************************************/ CASE (AGATE_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = AGATE_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new AgatePattern()); dynamic_cast(Pigment->pattern.get())->agateTurbScale = 1.0; Check_Turb(Pigment->pattern->warps, Pigment->pattern->HasSpecialTurbulenceHandling()); // agate needs Octaves, Lambda etc., and handles the pattern itself @@ -3239,13 +3079,13 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. CASE (MARBLE_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = MARBLE_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new MarblePattern()); END_CASE CASE (MANDEL_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = MANDEL_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new Mandel2Pattern()); dynamic_cast(Pigment->pattern.get())->maxIterations = Parse_Int_With_Minimum(1, "fractal iterations limit"); END_CASE @@ -3264,7 +3104,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. CASE (WOOD_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = WOOD_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new WoodPattern()); END_CASE @@ -3286,37 +3126,36 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. CASE (CHECKER_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = GENERIC_INTEGER_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new CheckerPattern()); Pigment->Blend_Map = Parse_Blend_List(2,Pigment->pattern->GetDefaultBlendMap(),kBlendMapType_Colour); END_CASE CASE (HEXAGON_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = GENERIC_INTEGER_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new HexagonPattern()); Pigment->Blend_Map = Parse_Blend_List(3,Pigment->pattern->GetDefaultBlendMap(),kBlendMapType_Colour); END_CASE CASE (SQUARE_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = GENERIC_INTEGER_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new SquarePattern()); Pigment->Blend_Map = Parse_Blend_List(4,Pigment->pattern->GetDefaultBlendMap(),kBlendMapType_Colour); END_CASE CASE (TRIANGULAR_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = GENERIC_INTEGER_PATTERN; + Pigment->Type = GENERIC_PATTERN; Pigment->pattern = PatternPtr(new TriangularPattern()); Pigment->Blend_Map = Parse_Blend_List(6,Pigment->pattern->GetDefaultBlendMap(),kBlendMapType_Colour); END_CASE CASE (IMAGE_MAP_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - Pigment->Type = BITMAP_PATTERN; - Pigment->pattern = PatternPtr(new ImagePattern()); - dynamic_cast(Pigment->pattern.get())->waveFrequency = 0.0; + Pigment->Type = IMAGE_MAP_PATTERN; + Pigment->pattern = PatternPtr(new ColourImagePattern()); Parse_Image_Map (Pigment); END_CASE @@ -3327,9 +3166,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. CASE (COLOUR_MAP_TOKEN) Warn_State(Token.Token_Id, PIGMENT_TOKEN); - if (Pigment->Type == GENERIC_INTEGER_PATTERN || - Pigment->Type == PLAIN_PATTERN || - Pigment->Type == BITMAP_PATTERN) + if (!Pigment->pattern->CanMap()) VersionWarning(150, "Cannot use color map with this pigment type."); Pigment->Blend_Map = Parse_Colour_Map (); END_CASE @@ -3363,7 +3200,7 @@ TNORMAL STUFF OUTSIDE NORMAL{} NOTE: Do not add new keywords to this section. Use 1.0 syntax only. ***********************************************************************/ CASE (BUMPS_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = BUMPS_PATTERN; Tnormal->pattern = PatternPtr(new BumpsPattern()); @@ -3371,7 +3208,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (DENTS_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = DENTS_PATTERN; Tnormal->pattern = PatternPtr(new DentsPattern()); @@ -3379,7 +3216,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (RIPPLES_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = RIPPLES_PATTERN; Tnormal->pattern = PatternPtr(new RipplesPattern()); @@ -3387,7 +3224,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (WAVES_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = WAVES_PATTERN; Tnormal->pattern = PatternPtr(new WavesPattern()); @@ -3395,7 +3232,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (WRINKLES_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = WRINKLES_PATTERN; Tnormal->pattern = PatternPtr(new WrinklesPattern()); @@ -3403,7 +3240,7 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (BUMP_MAP_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL Tnormal->Type = BITMAP_PATTERN; Tnormal->pattern = PatternPtr(new ImagePattern()); @@ -3412,23 +3249,31 @@ NOTE: Do not add new keywords to this section. Use 1.0 syntax only. END_CASE CASE (FREQUENCY_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL - if (!(Tnormal->Type == RIPPLES_PATTERN || Tnormal->Type == WAVES_PATTERN)) + pContinuousPattern = dynamic_cast(Tnormal->pattern.get()); + if (pContinuousPattern != NULL) + pContinuousPattern->waveFrequency = Parse_Float(); + else + { if (sceneData->EffectiveLanguageVersion() >= 150) VersionWarning(150, "Cannot use frequency with this normal."); - pContinuousPattern = dynamic_cast(Tnormal->pattern.get()); - pContinuousPattern->waveFrequency = Parse_Float(); + Parse_Float(); + } END_CASE CASE (PHASE_TOKEN) - Warn_State(Token.Token_Id, TNORMAL_TOKEN); + Warn_State(Token.Token_Id, NORMAL_TOKEN); ADD_TNORMAL - if (!(Tnormal->Type == RIPPLES_PATTERN || Tnormal->Type == WAVES_PATTERN)) + pContinuousPattern = dynamic_cast(Tnormal->pattern.get()); + if (pContinuousPattern != NULL) + pContinuousPattern->wavePhase = Parse_Float(); + else + { if (sceneData->EffectiveLanguageVersion() >= 150) VersionWarning(150, "Cannot use phase with this normal."); - pContinuousPattern = dynamic_cast(Tnormal->pattern.get()); - pContinuousPattern->wavePhase = Parse_Float(); + Parse_Float(); + } END_CASE @@ -3671,10 +3516,9 @@ void Parser::Parse_Media(vector& medialist) Parse_Begin(); - EXPECT + EXPECT_ONE CASE(MEDIA_ID_TOKEN) IMediaObj = *(reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE @@ -3687,7 +3531,6 @@ void Parser::Parse_Media(vector& medialist) IMedia->Max_Samples = 10; IMedia->Sample_Method = 3; } - EXIT END_CASE END_EXPECT @@ -3877,18 +3720,16 @@ void Parser::Parse_Interior(InteriorPtr& interior) { Parse_Begin(); - EXPECT + EXPECT_ONE CASE(INTERIOR_ID_TOKEN) if(Token.Data != NULL) interior = InteriorPtr(new Interior(**reinterpret_cast(Token.Data))); else interior = InteriorPtr(new Interior()); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -3972,16 +3813,14 @@ void Parser::Parse_Interior(InteriorPtr& interior) void Parser::Parse_Media_Density_Pattern(PIGMENT** Density) { - EXPECT + EXPECT_ONE CASE (DENSITY_ID_TOKEN) *Density = Copy_Pigment (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE *Density = Create_Pigment(); UNGET - EXIT END_CASE END_EXPECT @@ -4032,16 +3871,14 @@ FOG *Parser::Parse_Fog() Parse_Begin(); - EXPECT + EXPECT_ONE CASE(FOG_ID_TOKEN) Fog = Copy_Fog (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET Fog = Create_Fog(); - EXIT END_CASE END_EXPECT @@ -4199,16 +4036,14 @@ RAINBOW *Parser::Parse_Rainbow() Parse_Begin(); - EXPECT + EXPECT_ONE CASE(RAINBOW_ID_TOKEN) Rainbow = Copy_Rainbow (reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET Rainbow = Create_Rainbow(); - EXIT END_CASE END_EXPECT @@ -4376,16 +4211,14 @@ SKYSPHERE *Parser::Parse_Skysphere() Parse_Begin(); - EXPECT + EXPECT_ONE CASE(SKYSPHERE_ID_TOKEN) Skysphere = Copy_Skysphere(reinterpret_cast(Token.Data)); - EXIT END_CASE OTHERWISE UNGET Skysphere = Create_Skysphere(); - EXIT END_CASE END_EXPECT @@ -4597,7 +4430,7 @@ void Parser::Parse_Warp (WarpList& warps) Parse_Begin(); - EXPECT + EXPECT_ONE CASE(TURBULENCE_TOKEN) New = Turb = new TurbulenceWarp(); Parse_Vector(Turb->Turbulence); @@ -4623,7 +4456,6 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE CASE(REPEAT_TOKEN) @@ -4679,7 +4511,6 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE CASE(BLACK_HOLE_TOKEN) @@ -4729,7 +4560,6 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE CASE(CYLINDRICAL_TOKEN) @@ -4750,7 +4580,6 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE CASE(SPHERICAL_TOKEN) @@ -4771,7 +4600,6 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE CASE(PLANAR_TOKEN) @@ -4783,7 +4611,6 @@ void Parser::Parse_Warp (WarpList& warps) Parse_Comma(); PlanarW->OffSet=Parse_Float(); } - EXIT END_CASE CASE(TOROIDAL_TOKEN) @@ -4808,13 +4635,11 @@ void Parser::Parse_Warp (WarpList& warps) EXIT END_CASE END_EXPECT - EXIT END_CASE // JN2007: Cubic warp CASE(CUBIC_TOKEN) New = new CubicWarp(); - EXIT END_CASE OTHERWISE @@ -4844,7 +4669,7 @@ void Parser::Parse_Material(MATERIAL *Material) Parse_Begin(); - EXPECT + EXPECT_ONE CASE(MATERIAL_ID_TOKEN) Temp = reinterpret_cast(Token.Data); Texture = Copy_Textures(Temp->Texture); @@ -4855,12 +4680,10 @@ void Parser::Parse_Material(MATERIAL *Material) Material->interior = InteriorPtr(new Interior(*(Temp->interior))); else Material->interior.reset(); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -4970,26 +4793,27 @@ void Parser::Parse_PatternFunction(TPATTERN *New) UCS2String ign; ContinuousPattern* pContinuousPattern; - EXPECT + EXPECT_ONE CASE (AGATE_TOKEN) - New->Type = AGATE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new AgatePattern()); Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); dynamic_cast(New->pattern.get())->agateTurbScale = 1.0; // TODO this is a job for a constructor - EXIT END_CASE CASE (BOZO_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BozoPattern()); - EXIT END_CASE CASE (FUNCTION_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new FunctionPattern()); dynamic_cast(New->pattern.get())->pFn = new FunctionVM::CustomFunction(dynamic_cast(sceneData->functionContextFactory), Parse_Function()); - EXIT + END_CASE + + CASE (USER_DEFINED_TOKEN) + Not_With("user_defined", "function pattern"); END_CASE CASE(PIGMENT_PATTERN_TOKEN) @@ -5000,41 +4824,36 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Parse_Pigment(&(dynamic_cast(New->pattern.get())->pPigment)); Post_Pigment(dynamic_cast(New->pattern.get())->pPigment); Parse_End(); - EXIT END_CASE CASE (GRANITE_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new GranitePattern()); - EXIT END_CASE CASE (LEOPARD_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new LeopardPattern()); - EXIT END_CASE CASE (MARBLE_TOKEN) - New->Type = MARBLE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new MarblePattern()); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (MANDEL_TOKEN) - New->Type = MANDEL_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern()); dynamic_cast(New->pattern.get())->maxIterations = Parse_Int_With_Minimum(1, "fractal iterations limit"); dynamic_cast(New->pattern.get())->interiorType = DEFAULT_FRACTAL_INTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorType = DEFAULT_FRACTAL_EXTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; - EXIT END_CASE CASE (JULIA_TOKEN) - New->Type = JULIA_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new JuliaPattern()); Parse_UV_Vect(dynamic_cast(New->pattern.get())->juliaCoord); Parse_Comma(); @@ -5043,39 +4862,33 @@ void Parser::Parse_PatternFunction(TPATTERN *New) dynamic_cast(New->pattern.get())->exteriorType = DEFAULT_FRACTAL_EXTERIOR_TYPE; dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; - EXIT END_CASE CASE (MAGNET_TOKEN) - New->Type = NO_PATTERN; + New->Type = GENERIC_PATTERN; i = (int)Parse_Float(); - EXPECT + EXPECT_ONE CASE (MANDEL_TOKEN) switch(i) { case 1: - New->Type = MAGNET1M_PATTERN; New->pattern = PatternPtr(new Magnet1MPattern()); break; case 2: - New->Type = MAGNET2M_PATTERN; New->pattern = PatternPtr(new Magnet2MPattern()); break; default: Error("Invalid magnet-mandel pattern type found. Valid types are 1 and 2."); break; } - EXIT END_CASE CASE (JULIA_TOKEN) switch(i) { case 1: - New->Type = MAGNET1J_PATTERN; New->pattern = PatternPtr(new Magnet1JPattern()); break; case 2: - New->Type = MAGNET2J_PATTERN; New->pattern = PatternPtr(new Magnet2JPattern()); break; default: @@ -5084,7 +4897,6 @@ void Parser::Parse_PatternFunction(TPATTERN *New) } Parse_UV_Vect(dynamic_cast(New->pattern.get())->juliaCoord); Parse_Comma(); - EXIT END_CASE OTHERWISE Error("Invalid magnet pattern found. Valid types are 'mandel' and 'julia'."); @@ -5097,13 +4909,11 @@ void Parser::Parse_PatternFunction(TPATTERN *New) dynamic_cast(New->pattern.get())->exteriorFactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR; dynamic_cast(New->pattern.get())->interiorFactor = DEFAULT_FRACTAL_INTERIOR_FACTOR; dynamic_cast(New->pattern.get())->maxIterations = Parse_Int_With_Minimum(1, "fractal iterations limit"); - EXIT END_CASE CASE (ONION_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new OnionPattern()); - EXIT END_CASE CASE (SPIRAL1_TOKEN) @@ -5111,7 +4921,6 @@ void Parser::Parse_PatternFunction(TPATTERN *New) New->pattern = PatternPtr(new Spiral1Pattern()); dynamic_cast(New->pattern.get())->arms = (short)Parse_Float (); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (SPIRAL2_TOKEN) @@ -5119,20 +4928,17 @@ void Parser::Parse_PatternFunction(TPATTERN *New) New->pattern = PatternPtr(new Spiral2Pattern()); dynamic_cast(New->pattern.get())->arms = (short)Parse_Float (); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (SPOTTED_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new SpottedPattern()); - EXIT END_CASE CASE (WOOD_TOKEN) - New->Type = WOOD_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new WoodPattern()); dynamic_cast(New->pattern.get())->waveType = kWaveType_Triangle; - EXIT END_CASE CASE (GRADIENT_TOKEN) @@ -5141,17 +4947,15 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Parse_Vector (Local_Vector); Local_Vector.normalize(); dynamic_cast(New->pattern.get())->gradient = Local_Vector; - EXIT END_CASE CASE (RADIAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new RadialPattern()); - EXIT END_CASE CASE (CRACKLE_TOKEN) - New->Type = CRACKLE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CracklePattern()); dynamic_cast(New->pattern.get())->crackleIsSolid = 0; dynamic_cast(New->pattern.get())->crackleForm[X] = -1; @@ -5159,7 +4963,6 @@ void Parser::Parse_PatternFunction(TPATTERN *New) dynamic_cast(New->pattern.get())->crackleForm[Z] = 0; dynamic_cast(New->pattern.get())->crackleMetric = 2; dynamic_cast(New->pattern.get())->crackleOffset = 0; - EXIT END_CASE // TODO VERIFY - COLOUR is not accepted, is that ok? @@ -5167,7 +4970,7 @@ void Parser::Parse_PatternFunction(TPATTERN *New) // UV_MAPPING_TOKEN is not accepted, as it requires UV mapping information, which can't be passed to a function CASE (CHECKER_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CheckerPattern()); // TODO VERIFY - this differs from regular pattern parsing (Blend Map), is that ok? END_CASE @@ -5179,38 +4982,34 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Parse_Bound_Clip(tempObjects, false); if(tempObjects.size() != 1) Error ("object or object identifier expected."); - New->Type = OBJECT_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new ObjectPattern()); dynamic_cast(New->pattern.get())->pObject = tempObjects[0]; // TODO VERIFY - this differs from regular pattern parsing (Blend Map), is that ok? Parse_End(); - EXIT } END_CASE CASE (CELLS_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CellsPattern()); - EXIT END_CASE CASE (BRICK_TOKEN) - if (New->Type!=BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) { - New->Type = BRICK_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BrickPattern()); dynamic_cast(New->pattern.get())->brickSize = Vector3d(8.0,3.0,4.5); dynamic_cast(New->pattern.get())->mortar=0.5-EPSILON*2.0; } // TODO VERIFY - this differs from regular pattern parsing (Blend Map), is that ok? - EXIT END_CASE CASE (HEXAGON_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new HexagonPattern()); // TODO VERIFY - this differs from regular pattern parsing (Blend Map), is that ok? - EXIT END_CASE // TODO VERIFY - SQUARE_TOKEN is not accepted, is that ok? @@ -5219,10 +5018,9 @@ void Parser::Parse_PatternFunction(TPATTERN *New) // JN2007: Cubic pattern CASE (CUBIC_TOKEN) - New->Type = GENERIC_INTEGER_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CubicPattern()); // TODO VERIFY - this differs from regular pattern parsing (Blend Map), is that ok? - EXIT END_CASE // TODO VERIFY - IMAGE_MAP_TOKEN is not accepted, is that ok? @@ -5232,31 +5030,26 @@ void Parser::Parse_PatternFunction(TPATTERN *New) CASE (WAVES_TOKEN) New->Type = WAVES_PATTERN; New->pattern = PatternPtr(new WavesPattern()); - EXIT END_CASE CASE (RIPPLES_TOKEN) New->Type = RIPPLES_PATTERN; New->pattern = PatternPtr(new RipplesPattern()); - EXIT END_CASE CASE (WRINKLES_TOKEN) New->Type = WRINKLES_PATTERN; New->pattern = PatternPtr(new WrinklesPattern()); - EXIT END_CASE CASE (BUMPS_TOKEN) New->Type = BUMPS_PATTERN; New->pattern = PatternPtr(new BumpsPattern()); - EXIT END_CASE CASE (DENTS_TOKEN) New->Type = DENTS_PATTERN; New->pattern = PatternPtr(new DentsPattern()); - EXIT END_CASE CASE (QUILTED_TOKEN) @@ -5265,7 +5058,6 @@ void Parser::Parse_PatternFunction(TPATTERN *New) dynamic_cast(New->pattern.get())->Control0 = 1.0; dynamic_cast(New->pattern.get())->Control1 = 1.0; dynamic_cast(New->pattern.get())->waveFrequency = 0.0; - EXIT END_CASE // FACETS_TOKEN is not accepted, as it requires normal vector information, which can't be passed to a function @@ -5274,40 +5066,35 @@ void Parser::Parse_PatternFunction(TPATTERN *New) CASE (IMAGE_PATTERN_TOKEN) // TODO VERIFY - this differs from regular pattern parsing (destruction of old image), is that ok? - New->Type = IMAGE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new ImagePattern()); dynamic_cast(New->pattern.get())->waveFrequency = 0.0; Parse_Image_Pattern (New); - EXIT END_CASE CASE (PLANAR_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new PlanarPattern()); - EXIT END_CASE CASE (BOXED_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new BoxedPattern()); - EXIT END_CASE CASE (SPHERICAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new SphericalPattern()); - EXIT END_CASE CASE (CYLINDRICAL_TOKEN) New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new CylindricalPattern()); - EXIT END_CASE CASE (DENSITY_FILE_TOKEN) // TODO VERIFY - this differs from regular pattern parsing (destruction of old density file), is that ok? - New->Type = DENSITY_FILE_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new DensityFilePattern()); dynamic_cast(New->pattern.get())->densityFile = Create_Density_File(); GET(DF3_TOKEN); @@ -5318,7 +5105,6 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Error("Cannot read media density file."); Read_Density_File(dfile, dynamic_cast(New->pattern.get())->densityFile); } - EXIT END_CASE // SLOPE_TOKEN is not accepted, as it requires normal vector information, which can't be passed to a function @@ -5326,7 +5112,7 @@ void Parser::Parse_PatternFunction(TPATTERN *New) // AOI_TOKEN is not accepted, as it requires normal vector information, which can't be passed to a function CASE (PAVEMENT_TOKEN) - New->Type = PAVEMENT_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new PavementPattern()); dynamic_cast(New->pattern.get())->Side = 3; dynamic_cast(New->pattern.get())->Tile = 1; @@ -5334,14 +5120,12 @@ void Parser::Parse_PatternFunction(TPATTERN *New) dynamic_cast(New->pattern.get())->Exterior = 0; dynamic_cast(New->pattern.get())->Interior = 0; dynamic_cast(New->pattern.get())->Form = 0; - EXIT END_CASE CASE (TILING_TOKEN) - New->Type = TILING_PATTERN; + New->Type = GENERIC_PATTERN; New->pattern = PatternPtr(new TilingPattern()); dynamic_cast(New->pattern.get())->tilingType = (unsigned char)Parse_Float(); - EXIT END_CASE CASE (POTENTIAL_TOKEN) @@ -5369,13 +5153,11 @@ void Parser::Parse_PatternFunction(TPATTERN *New) END_CASE END_EXPECT - EXIT } END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT @@ -5383,27 +5165,18 @@ void Parser::Parse_PatternFunction(TPATTERN *New) // ACCURACY_TOKEN is not accepted, as it is only useful for normal perturbations CASE (SOLID_TOKEN) - if (New->Type != CRACKLE_PATTERN ) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->crackleIsSolid = 1; + else Only_In("solid", "crackle"); - dynamic_cast(New->pattern.get())->crackleIsSolid = 1; END_CASE CASE (EXTERIOR_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN) || - (New->Type == MAGNET1M_PATTERN) || (New->Type == MAGNET2M_PATTERN) || - (New->Type == MAGNET1J_PATTERN) || (New->Type == MAGNET2J_PATTERN) || - (New->Type == PAVEMENT_PATTERN))) - { - Only_In("exterior", "mandel, julia, magnet or pavement"); - } - else if (New->Type == PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->Exterior = (unsigned char)Parse_Float(); } - else + else if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->exteriorType = (int)Parse_Float(); if((dynamic_cast(New->pattern.get())->exteriorType < 0) || (dynamic_cast(New->pattern.get())->exteriorType > 6)) @@ -5411,24 +5184,18 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Parse_Comma(); dynamic_cast(New->pattern.get())->exteriorFactor = Parse_Float(); } - END_CASE - - CASE (INTERIOR_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN) || - (New->Type == MAGNET1M_PATTERN) || (New->Type == MAGNET2M_PATTERN) || - (New->Type == MAGNET1J_PATTERN) || (New->Type == MAGNET2J_PATTERN) || - (New->Type == PAVEMENT_PATTERN))) + else { Only_In("exterior", "mandel, julia, magnet or pavement"); } - else if (New->Type == PAVEMENT_PATTERN) + END_CASE + + CASE (INTERIOR_TOKEN) + if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->Interior = (unsigned char)Parse_Float(); } - else + else if (dynamic_cast(New->pattern.get())) { dynamic_cast(New->pattern.get())->interiorType = (int)Parse_Float(); if((dynamic_cast(New->pattern.get())->interiorType < 0) || (dynamic_cast(New->pattern.get())->interiorType > 6)) @@ -5436,45 +5203,35 @@ void Parser::Parse_PatternFunction(TPATTERN *New) Parse_Comma(); dynamic_cast(New->pattern.get())->interiorFactor = Parse_Float(); } - END_CASE - - CASE (EXPONENT_TOKEN) - if(!((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN) || - (New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN))) + else { - Only_In("exponent", "mandel or julia"); + Only_In("exterior", "mandel, julia, magnet or pavement"); } + END_CASE - if((New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || - (New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN)) + CASE (EXPONENT_TOKEN) + if (dynamic_cast(New->pattern.get())) { i = (int)Parse_Float(); switch(i) { case 2: - New->Type = JULIA_PATTERN; New->pattern = PatternPtr(new JuliaPattern(*dynamic_cast(New->pattern.get()))); break; case 3: - New->Type = JULIA3_PATTERN; New->pattern = PatternPtr(new Julia3Pattern(*dynamic_cast(New->pattern.get()))); break; case 4: - New->Type = JULIA4_PATTERN; New->pattern = PatternPtr(new Julia4Pattern(*dynamic_cast(New->pattern.get()))); break; default: if((i > 4) && (i <= kFractalMaxExponent)) { - New->Type = JULIAX_PATTERN; New->pattern = PatternPtr(new JuliaXPattern(*dynamic_cast(New->pattern.get()))); dynamic_cast(New->pattern.get())->fractalExponent = i; } else { - New->Type = JULIA_PATTERN; New->pattern = PatternPtr(new JuliaPattern(*dynamic_cast(New->pattern.get()))); Warning("Invalid julia pattern exponent found. Supported exponents are 2 to %i.\n" "Using default exponent 2.", kFractalMaxExponent); @@ -5482,34 +5239,28 @@ void Parser::Parse_PatternFunction(TPATTERN *New) break; } } - else if((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || - (New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN)) + else if (dynamic_cast(New->pattern.get())) { i = (int)Parse_Float(); switch(i) { case 2: - New->Type = MANDEL_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern(*dynamic_cast(New->pattern.get()))); break; case 3: - New->Type = MANDEL3_PATTERN; New->pattern = PatternPtr(new Mandel3Pattern(*dynamic_cast(New->pattern.get()))); break; case 4: - New->Type = MANDEL4_PATTERN; New->pattern = PatternPtr(new Mandel4Pattern(*dynamic_cast(New->pattern.get()))); break; default: if((i > 4) && (i <= kFractalMaxExponent)) { - New->Type = MANDELX_PATTERN; New->pattern = PatternPtr(new MandelXPattern(*dynamic_cast(New->pattern.get()))); dynamic_cast(New->pattern.get())->fractalExponent = i; } else { - New->Type = MANDEL_PATTERN; New->pattern = PatternPtr(new Mandel2Pattern(*dynamic_cast(New->pattern.get()))); Warning("Invalid mandel pattern exponent found. Supported exponents are 2 to %i.\n" "Using default exponent 2.", kFractalMaxExponent); @@ -5517,27 +5268,31 @@ void Parser::Parse_PatternFunction(TPATTERN *New) break; } } + else + Only_In("exponent", "mandel or julia"); END_CASE CASE (COORDS_TOKEN) - if (New->Type != FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->facetsCoords = Parse_Float(); + else Only_In("coords", "facets"); - dynamic_cast(New->pattern.get())->facetsCoords = Parse_Float(); END_CASE CASE (SIZE_TOKEN) - if (New->Type != FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->facetsSize = Parse_Float(); + else Only_In("size", "facets"); - dynamic_cast(New->pattern.get())->facetsSize = Parse_Float(); END_CASE CASE (METRIC_TOKEN) - if (New->Type == FACETS_PATTERN ) + if (dynamic_cast(New->pattern.get())) { Parse_Vector(Local_Vector); dynamic_cast(New->pattern.get())->facetsMetric = Local_Vector[X]; } - else if ( New->Type == CRACKLE_PATTERN ) + else if (dynamic_cast(New->pattern.get())) { // Vector for backwards compatibility // the only component used was always X. @@ -5549,18 +5304,19 @@ void Parser::Parse_PatternFunction(TPATTERN *New) END_CASE CASE (FORM_TOKEN) - if (New->Type == CRACKLE_PATTERN) + if (dynamic_cast(New->pattern.get())) Parse_Vector( dynamic_cast(New->pattern.get())->crackleForm ); - else if (New->Type == PAVEMENT_PATTERN) + else if (dynamic_cast(New->pattern.get())) dynamic_cast(New->pattern.get())->Form = ((unsigned char)Parse_Float()); else Only_In("form", "crackle or pavement"); END_CASE CASE (OFFSET_TOKEN) - if (New->Type != CRACKLE_PATTERN ) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->crackleOffset = Parse_Float(); + else Only_In("offset", "crackle"); - dynamic_cast(New->pattern.get())->crackleOffset = Parse_Float(); END_CASE CASE (TURBULENCE_TOKEN) @@ -5581,15 +5337,17 @@ void Parser::Parse_PatternFunction(TPATTERN *New) // TODO VERIFY - QUICK_COLOUR is not accepted, is that ok? CASE (CONTROL0_TOKEN) - if (New->Type != QUILTED_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Control0 = Parse_Float (); + else Not_With ("control0","this pattern"); - dynamic_cast(New->pattern.get())->Control0 = Parse_Float (); END_CASE CASE (CONTROL1_TOKEN) - if (New->Type != QUILTED_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Control1 = Parse_Float (); + else Not_With ("control1","this pattern"); - dynamic_cast(New->pattern.get())->Control1 = Parse_Float (); END_CASE CASE (OCTAVES_TOKEN) @@ -5617,7 +5375,7 @@ void Parser::Parse_PatternFunction(TPATTERN *New) pContinuousPattern->waveFrequency = Parse_Float(); else { - Warning("frequrency has no effect on discrete patterns"); + Warning("frequency has no effect on discrete patterns"); Parse_Float(); } END_CASE @@ -5700,46 +5458,53 @@ void Parser::Parse_PatternFunction(TPATTERN *New) END_CASE CASE (AGATE_TURB_TOKEN) - if (New->Type != AGATE_PATTERN) + if (dynamic_cast(New->pattern.get())) + { + dynamic_cast(New->pattern.get())->agateTurbScale = Parse_Float(); + Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); // agate needs Octaves, Lambda etc. + } + else Not_With ("agate_turb","non-agate"); - dynamic_cast(New->pattern.get())->agateTurbScale = Parse_Float(); - Check_Turb(New->pattern->warps, New->pattern->HasSpecialTurbulenceHandling()); /* agate needs Octaves, Lambda etc. */ END_CASE CASE (BRICK_SIZE_TOKEN) - if (New->Type != BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) Not_With ("brick_size","non-brick"); Parse_Vector(dynamic_cast(New->pattern.get())->brickSize); END_CASE CASE (MORTAR_TOKEN) - if (New->Type != BRICK_PATTERN) + if (!dynamic_cast(New->pattern.get())) Not_With ("mortar","non-brick"); dynamic_cast(New->pattern.get())->mortar = Parse_Float()-EPSILON*2.0; END_CASE CASE (INTERPOLATE_TOKEN) - if (New->Type != DENSITY_FILE_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->densityFile->Interpolation = (int)Parse_Float(); + else Not_With ("interpolate","non-density_file"); - dynamic_cast(New->pattern.get())->densityFile->Interpolation = (int)Parse_Float(); END_CASE CASE (NUMBER_OF_SIDES_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Side = (unsigned char)Parse_Float(); + else Only_In("number_of_sides","pavement"); - dynamic_cast(New->pattern.get())->Side=(unsigned char)Parse_Float(); END_CASE CASE (NUMBER_OF_TILES_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Tile = (unsigned char)Parse_Float(); + else Only_In("number_of_tiles","pavement"); - dynamic_cast(New->pattern.get())->Tile=(unsigned char)Parse_Float(); END_CASE CASE (PATTERN_TOKEN) - if (New->Type != PAVEMENT_PATTERN) + if (dynamic_cast(New->pattern.get())) + dynamic_cast(New->pattern.get())->Number = (unsigned char)Parse_Float(); + else Only_In("pattern","pavement"); - dynamic_cast(New->pattern.get())->Number=(unsigned char)Parse_Float(); END_CASE CASE (WARP_TOKEN) diff --git a/source/parser/parser_obj.cpp b/source/parser/parser_obj.cpp index b7e84b5b0..cabcdc2c8 100644 --- a/source/parser/parser_obj.cpp +++ b/source/parser/parser_obj.cpp @@ -326,7 +326,7 @@ void Parser::Parse_Obj (Mesh* mesh) else ++vertex; } - if ((haveVertices > 3) && (havePolygonFaces)) + if ((haveVertices > 3) && !havePolygonFaces) { Warning ("Non-triangular faces found in obj file %s. Faces will only import properly if they are convex and planar.", UCS2toASCIIString(fileName).c_str()); havePolygonFaces = true; @@ -436,9 +436,7 @@ void Parser::Parse_Obj (Mesh* mesh) } // close obj file - - if (textStream) - delete textStream; + delete textStream; size_t smoothFaces = faceList.size(); faceList.insert (faceList.end(), flatFaceList.begin(), flatFaceList.end()); diff --git a/source/parser/parser_strings.cpp b/source/parser/parser_strings.cpp index fea92126a..1fd450cfd 100644 --- a/source/parser/parser_strings.cpp +++ b/source/parser/parser_strings.cpp @@ -484,12 +484,11 @@ UCS2 *Parser::Parse_Datetime(bool pathname) GET(LEFT_PAREN_TOKEN); std::time_t timestamp = floor((Parse_Float() + (365*30+7)) * 24*60*60 + 0.5); Parse_Comma(); - EXPECT + EXPECT_ONE CASE(RIGHT_PAREN_TOKEN) CallFree = false; // we use GMT as some platforms (e.g. windows) have different ideas of what to print when handling '%z'. FormatStr = (char *)"%Y-%m-%d %H:%M:%SZ"; - EXIT END_CASE OTHERWISE @@ -507,7 +506,6 @@ UCS2 *Parser::Parse_Datetime(bool pathname) Error("Format string too long."); } GET(RIGHT_PAREN_TOKEN); - EXIT END_CASE END_EXPECT @@ -873,8 +871,7 @@ UCS2 *Parser::String_Literal_To_UCS2(const char *str, bool pathname) break; default: char_string[index_out] = char_array[index_in]; - if ( char_array ) - POV_FREE(char_array); + POV_FREE(char_array); char_array = NULL; Error( "Illegal escape sequence in string." ); break; @@ -1267,7 +1264,7 @@ void Parser::UCS2_strupr(UCS2 *str) } if(err == true) - Warning("Non-ASCII charcater in string, strupr may not work as expected."); + Warning("Non-ASCII character in string, strupr may not work as expected."); } @@ -1305,7 +1302,7 @@ void Parser::UCS2_strlwr(UCS2 *str) } if(err == true) - Warning("Non-ASCII charcater in string, strlwr may not work as expected."); + Warning("Non-ASCII character in string, strlwr may not work as expected."); } UCS2 *Parser::UCS2_strdup(const UCS2 *s) diff --git a/source/parser/parser_tokenizer.cpp b/source/parser/parser_tokenizer.cpp index 7d0ca01b1..c1f4f07cc 100644 --- a/source/parser/parser_tokenizer.cpp +++ b/source/parser/parser_tokenizer.cpp @@ -157,6 +157,7 @@ void Parser::pre_init_tokenizer () Token.Token_File_Pos.offset = 0; Token.Token_Col_No = 0; Token.Token_String = NULL; + Token.freeString = false; Token.Unget_Token = false; Token.End_Of_File = false; Token.Data = NULL; @@ -176,8 +177,8 @@ void Parser::pre_init_tokenizer () Skipping = false; Inside_Ifdef = false; Inside_MacroDef = false; - Inside_IdentFn = kIdentifierModeUndefined; Parsing_Directive = false; + parseRawIdentifiers = false; Cond_Stack = NULL; Table_Index = -1; @@ -186,7 +187,7 @@ void Parser::pre_init_tokenizer () // TODO - on modern machines it may be faster to do the comparisons for each token // than to access the conversion table. - for(i = 0; i < LAST_TOKEN; i++) + for(i = 0; i < TOKEN_COUNT; i++) { Conversion_Util_Table[i] = i; if(i < FLOAT_FUNCT_TOKEN) @@ -326,6 +327,8 @@ void Parser::Get_Token () Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; while (Token.Token_Id == END_OF_FILE_TOKEN) { @@ -340,6 +343,8 @@ void Parser::Get_Token () { Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Token.End_Of_File = true; return; } @@ -351,7 +356,8 @@ void Parser::Get_Token () Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; - + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Token.End_Of_File = true; return; @@ -627,26 +633,6 @@ void Parser::Get_Token () case '_': Echo_ungetc(c); Read_Symbol (); - if (!Parsing_Directive && (Inside_IdentFn == kIdentifierModeUndefined) && ((Token.Token_Id == LOCAL_TOKEN) || (Token.Token_Id == GLOBAL_TOKEN))) - { - if (!Skip_Spaces()) - Error("Expected '(', end of file reached instead", c2); - c2 = Echo_getc(); - if (c2 != '(') - Error("Expected '(', found '%c' instead", c2); - if (!Skip_Spaces()) - Error("Expected 'identifier', end of file reached instead", c2); - - Inside_IdentFn = (Token.Token_Id == LOCAL_TOKEN) ? kIdentifierModeLocal : kIdentifierModeGlobal; - Read_Symbol(); - Inside_IdentFn = kIdentifierModeUndefined; - - if (!Skip_Spaces()) - Error("Expected ')', end of file reached instead", c2); - c2 = Echo_getc(); - if (c2 != ')') - Error("Expected ')', found '%c' instead", c2); - } break; case '\t': case '\r': @@ -1050,8 +1036,6 @@ void Parser::Read_String_Literal() End_String(); Write_Token(STRING_LITERAL_TOKEN, col); - - Token.Token_String = String; } @@ -1273,6 +1257,9 @@ void Parser::Read_Symbol() SYM_ENTRY *Temp_Entry; POV_PARAM *Par; DBL val; + SYM_TABLE *table = NULL; + char *dictIndex = NULL; + int pseudoDictionary = -1; Begin_String_Fast(); @@ -1300,137 +1287,281 @@ void Parser::Read_Symbol() End_String_Fast(); /* If its a reserved keyword, write it and return */ - if ( (Temp_Entry = Find_Symbol(0,String)) != NULL) + if ( (Temp_Entry = Find_Symbol(SYM_TABLE_RESERVED,String)) != NULL) { - if (!Inside_Ifdef || ((sceneData->EffectiveLanguageVersion() >= 3.71) && - ((Temp_Entry->Token_Number == LOCAL_TOKEN) || (Temp_Entry->Token_Number == GLOBAL_TOKEN)))) + if (!Parsing_Directive && (Temp_Entry->Token_Number == LOCAL_TOKEN)) { - Write_Token (Temp_Entry->Token_Number, Token.Token_Col_No); - return; + pseudoDictionary = Table_Index; } - else + else if (!Parsing_Directive && (Temp_Entry->Token_Number == GLOBAL_TOKEN)) + { + pseudoDictionary = SYM_TABLE_GLOBAL; + } + else if (Inside_Ifdef) { Warning("Tried to test whether a reserved keyword is defined. Test result may not be what you expect."); } + else + { + Write_Token (Temp_Entry->Token_Number, Token.Token_Col_No); + return; + } } - if (!Skipping) + if (!Skipping && !parseRawIdentifiers) { - /* Search tables from newest to oldest */ - int firstIndex = Table_Index; - int lastIndex = 1; // index 0 is reserved for reserved words, not identifiers - if (Inside_IdentFn == kIdentifierModeGlobal) - // if inside "global()" pseudo-function, just test the global table - firstIndex = 1; - else if (Inside_IdentFn == kIdentifierModeLocal) - // if inside "local()" pseudo-function, just test the most local table - lastIndex = Table_Index; - for (Local_Index = firstIndex; Local_Index >= lastIndex; Local_Index--) + if (pseudoDictionary >= 0) { - /* See if it's a previously declared identifier. */ - if ((Temp_Entry = Find_Symbol(Local_Index,String)) != NULL) - { - if (Temp_Entry->deprecated && !Temp_Entry->deprecatedShown) - { - Temp_Entry->deprecatedShown = Temp_Entry->deprecatedOnce; - Warning("%s", Temp_Entry->Deprecation_Message); - } + Token.Token_Id = DICTIONARY_ID_TOKEN; + Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; + Token.NumberPtr = &(Temp_Entry->Token_Number); + Token.DataPtr = &(Temp_Entry->Data); - if ((Temp_Entry->Token_Number==MACRO_ID_TOKEN) && (!Inside_Ifdef)) + table = NULL; + } + else + { + /* Search tables from newest to oldest */ + int firstIndex = Table_Index; + int lastIndex = SYM_TABLE_RESERVED+1; // index SYM_TABLE_RESERVED is reserved for reserved words, not identifiers + for (Local_Index = firstIndex; Local_Index >= lastIndex; Local_Index--) + { + /* See if it's a previously declared identifier. */ + if ((Temp_Entry = Find_Symbol(Local_Index,String)) != NULL) { - Token.Data = Temp_Entry->Data; - if (Ok_To_Declare) + if (Temp_Entry->deprecated && !Temp_Entry->deprecatedShown) { - Invoke_Macro(); + Temp_Entry->deprecatedShown = Temp_Entry->deprecatedOnce; + Warning("%s", Temp_Entry->Deprecation_Message); } - else + + if ((Temp_Entry->Token_Number==MACRO_ID_TOKEN) && (!Inside_Ifdef)) { - Token.Token_Id=MACRO_ID_TOKEN; - Token.is_array_elem = false; - Token.NumberPtr = &(Temp_Entry->Token_Number); - Token.DataPtr = &(Temp_Entry->Data); - Write_Token (Token.Token_Id, Token.Token_Col_No); + Token.Data = Temp_Entry->Data; + if (Ok_To_Declare) + { + Invoke_Macro(); + } + else + { + Token.Token_Id=MACRO_ID_TOKEN; + Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; + Token.NumberPtr = &(Temp_Entry->Token_Number); + Token.DataPtr = &(Temp_Entry->Data); + Write_Token (Token.Token_Id, Token.Token_Col_No, Tables[Local_Index]); - Token.Table_Index = Local_Index; + Token.context = Local_Index; + } + return; } - return; - } - Token.Token_Id = Temp_Entry->Token_Number; - Token.is_array_elem = false; - Token.NumberPtr = &(Temp_Entry->Token_Number); - Token.DataPtr = &(Temp_Entry->Data); + Token.Token_Id = Temp_Entry->Token_Number; + Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; + Token.NumberPtr = &(Temp_Entry->Token_Number); + Token.DataPtr = &(Temp_Entry->Data); - while ((Token.Token_Id==PARAMETER_ID_TOKEN) || - (Token.Token_Id==ARRAY_ID_TOKEN)) - { - if (Token.Token_Id==ARRAY_ID_TOKEN) - { - Skip_Spaces(); - c = Echo_getc(); - Echo_ungetc(c); + table = Tables[Local_Index]; - if (c!='[') + break; + } + } + } + + if (table || (pseudoDictionary >= 0)) + { + bool breakLoop = false; + while (!breakLoop) + { + switch (Token.Token_Id) + { + case ARRAY_ID_TOKEN: { - break; - } + if (dictIndex) + POV_FREE (dictIndex); + + Skip_Spaces(); + c = Echo_getc(); + Echo_ungetc(c); + + if (c!='[') + { + breakLoop = true; + break; + } + + a = reinterpret_cast(*(Token.DataPtr)); + j = 0; + + for (i=0; i <= a->Dims; i++) + { + GET(LEFT_SQUARE_TOKEN) + val=Parse_Float(); + k=(int)(val + EPSILON); + + if ((k < 0) || (val < -EPSILON)) + { + Error("Negative subscript"); + } + + if (k >= a->Sizes[i]) + { + if (a->resizable) + { + POV_PARSER_ASSERT (a->Dims == 0); + a->DataPtrs.resize (k+1); + a->Sizes[0] = a->DataPtrs.size(); + } + else + Error("Array subscript out of range"); + } + j += k * a->Mags[i]; + GET(RIGHT_SQUARE_TOKEN) + } - a = reinterpret_cast(*(Token.DataPtr)); - j = 0; + if (!LValue_Ok && !Inside_Ifdef) + { + if (a->DataPtrs[j] == NULL) + Error("Attempt to access uninitialized array element."); + } - for (i=0; i <= a->Dims; i++) + Token.DataPtr = &(a->DataPtrs[j]); + Token.is_mixed_array_elem = !a->Types.empty(); + if (Token.is_mixed_array_elem) + Token.NumberPtr = &(a->Types[j]); + else + Token.NumberPtr = &(a->Type); + Token.Token_Id = *Token.NumberPtr; + Token.is_array_elem = true; + Token.is_dictionary_elem = false; + } + break; + + case DICTIONARY_ID_TOKEN: { - GET(LEFT_SQUARE_TOKEN) - val=Parse_Float(); - k=(int)(val + EPSILON); + if (dictIndex) + POV_FREE (dictIndex); + + Skip_Spaces(); + c = Echo_getc(); + Echo_ungetc(c); + + if (pseudoDictionary >= 0) + { + table = Tables [pseudoDictionary]; + pseudoDictionary = -1; + } + else + table = reinterpret_cast(*(Token.DataPtr)); - if ((k < 0) || (val < -EPSILON)) + if (c =='.') { - Error("Negative subscript"); + if (table == NULL) + { + POV_PARSER_ASSERT (Token.is_array_elem); + Error ("Attempt to access uninitialized array element."); + } + + GET (PERIOD_TOKEN) + bool oldParseRawIdentifiers = parseRawIdentifiers; + parseRawIdentifiers = true; + Get_Token (); + parseRawIdentifiers = oldParseRawIdentifiers; + + if (Token.Token_Id != IDENTIFIER_TOKEN) + Expectation_Error ("dictionary element identifier"); + + Temp_Entry = Find_Symbol (table, Token.Token_String); } + else if (c == '[') + { + if (table == NULL) + { + POV_PARSER_ASSERT (Token.is_array_elem); + Error ("Attempt to access uninitialized array element."); + } - if (k >= a->Sizes[i]) + GET(LEFT_SQUARE_TOKEN) + dictIndex = Parse_C_String(); + GET (RIGHT_SQUARE_TOKEN); + + Temp_Entry = Find_Symbol (table, dictIndex); + } + else + { + breakLoop = true; + break; + } + + if (Temp_Entry) { - Error("Array subscript out of range"); + Token.Token_Id = Temp_Entry->Token_Number; + Token.NumberPtr = &(Temp_Entry->Token_Number); + Token.DataPtr = &(Temp_Entry->Data); } - j += k * a->Mags[i]; - GET(RIGHT_SQUARE_TOKEN) + else + { + if (!LValue_Ok && !Inside_Ifdef) + Error ("Attempt to access uninitialized dictionary element."); + Token.Token_Id = IDENTIFIER_TOKEN; + Token.DataPtr = NULL; + Token.NumberPtr = NULL; + } + Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = true; } + break; - Token.DataPtr = &(a->DataPtrs[j]); - Token.NumberPtr = &(a->Type); - Token.Token_Id = a->Type; - Token.is_array_elem = true; - if (!LValue_Ok && !Inside_Ifdef) + case PARAMETER_ID_TOKEN: { - if (*Token.DataPtr == NULL) - Error("Attempt to access uninitialized array element."); + dictIndex = NULL; + + Par = reinterpret_cast(Temp_Entry->Data); + Token.Token_Id = *(Par->NumberPtr); + Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; + Token.NumberPtr = Par->NumberPtr; + Token.DataPtr = Par->DataPtr; } - } - else - { - Par = reinterpret_cast(Temp_Entry->Data); - Token.Token_Id = *(Par->NumberPtr); - Token.is_array_elem = false; - Token.NumberPtr = Par->NumberPtr; - Token.DataPtr = Par->DataPtr; - } + break; + + default: + breakLoop = true; + break; } + } - Write_Token (Token.Token_Id, Token.Token_Col_No); + Write_Token (Token.Token_Id, Token.Token_Col_No, table); - Token.Data = *(Token.DataPtr); - Token.Table_Index = Local_Index; - return; + if (Token.DataPtr != NULL) + Token.Data = *(Token.DataPtr); + Token.context = Local_Index; + if (dictIndex != NULL) + { + Token.Token_String = dictIndex; + Token.freeString = true; } + return; } } - Write_Token(IDENTIFIER_TOKEN, Token.Token_Col_No); + Write_Token (IDENTIFIER_TOKEN, Token.Token_Col_No); } -inline void Parser::Write_Token (TOKEN Token_Id, int col) +inline void Parser::Write_Token (TOKEN Token_Id, int col, SYM_TABLE *table) { + if (Token.freeString) + { + POV_FREE (Token.Token_String); + Token.freeString = false; + } Token.Token_File_Pos = Input_File->In_File->tellg(); Token.Token_Col_No = col; Token.FileHandle = Input_File->In_File; @@ -1438,6 +1569,7 @@ inline void Parser::Write_Token (TOKEN Token_Id, int col) Token.Data = NULL; Token.Token_Id = Conversion_Util_Table[Token_Id]; Token.Function_Id = Token_Id; + Token.table = table; } @@ -1712,6 +1844,8 @@ void Parser::Parse_Directive(int After_Hash) } Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; return; } @@ -1723,6 +1857,8 @@ void Parser::Parse_Directive(int After_Hash) { Token.Token_Id=HASH_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; } Token.Unget_Token = false; @@ -1731,7 +1867,8 @@ void Parser::Parse_Directive(int After_Hash) Parsing_Directive = true; - EXPECT + EXPECT // we're normally running this loop only once, but a few directives cause it to be looped + CASE(IFDEF_TOKEN) Parsing_Directive = false; Inc_CS_Index(); @@ -1881,6 +2018,8 @@ void Parser::Parse_Directive(int After_Hash) Cond_Stack[CS_Index].Cond_Type = ELSE_COND; Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET break; @@ -1894,6 +2033,8 @@ void Parser::Parse_Directive(int After_Hash) { Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET } break; @@ -1920,6 +2061,8 @@ void Parser::Parse_Directive(int After_Hash) Cond_Stack[CS_Index].Cond_Type=IF_TRUE_COND; Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET } else @@ -1951,7 +2094,7 @@ void Parser::Parse_Directive(int After_Hash) Cond_Stack[CS_Index].Switch_Value=Parse_Cond_Param(); Cond_Stack[CS_Index].Cond_Type=SWITCH_COND; Cond_Stack[CS_Index].Switch_Case_Ok_Flag=false; - EXPECT + EXPECT_ONE // NOTE: We actually expect a "#case" or "#range" here; however, this will trigger a nested call // to Parse_Directive, so we'll encounter that CASE_TOKEN or RANGE_TOKEN here only by courtesy of the // respective handler, which will UNGET the token and inform us via the Switch_Case_Ok_Flag @@ -1981,7 +2124,6 @@ void Parser::Parse_Directive(int After_Hash) Cond_Stack[CS_Index].Cond_Type=CASE_FALSE_COND; Skip_Tokens(CASE_FALSE_COND); } - EXIT END_CASE OTHERWISE @@ -2024,6 +2166,8 @@ void Parser::Parse_Directive(int After_Hash) { Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET } } @@ -2059,6 +2203,8 @@ void Parser::Parse_Directive(int After_Hash) case IF_FALSE_COND: Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET // FALLTHROUGH case IF_TRUE_COND: @@ -2099,6 +2245,8 @@ void Parser::Parse_Directive(int After_Hash) { Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/ Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; UNGET } break; @@ -2459,24 +2607,24 @@ void Parser::Parse_Directive(int After_Hash) else { Ok_To_Declare = false; - EXPECT + EXPECT_ONE CASE (IDENTIFIER_TOKEN) Warning("Attempt to undef unknown identifier"); - EXIT END_CASE CASE2 (MACRO_ID_TOKEN, PARAMETER_ID_TOKEN) CASE3 (FILE_ID_TOKEN, FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN) // These have to match Parse_Declare in parse.cpp! [trf] - CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) + CASE4 (NORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN) CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN) CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN) CASE4 (DENSITY_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_MAP_ID_TOKEN, UV_ID_TOKEN) CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN) - CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN) - Remove_Symbol (Token.Table_Index, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id); - EXIT + CASE3 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN, DICTIONARY_ID_TOKEN) + Remove_Symbol (Token.table, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id); + if (Token.is_mixed_array_elem) + *Token.NumberPtr = IDENTIFIER_TOKEN; END_CASE CASE2 (VECTOR_FUNCT_TOKEN, FLOAT_FUNCT_TOKEN) @@ -2484,14 +2632,15 @@ void Parser::Parse_Directive(int After_Hash) { case VECTOR_ID_TOKEN: case FLOAT_ID_TOKEN: - Remove_Symbol (Token.Table_Index, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id); + Remove_Symbol (Token.table, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id); + if (Token.is_mixed_array_elem) + *Token.NumberPtr = IDENTIFIER_TOKEN; break; default: Parse_Error(IDENTIFIER_TOKEN); break; } - EXIT END_CASE OTHERWISE @@ -2552,6 +2701,8 @@ void Parser::Parse_Directive(int After_Hash) { Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; } } @@ -2619,7 +2770,8 @@ void Parser::Open_Include() Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; - + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; } @@ -2660,6 +2812,8 @@ void Parser::Skip_Tokens(COND_TYPE cond) { Token.Token_Id=END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Token.Unget_Token=false; } else @@ -2722,6 +2876,8 @@ void Parser::Break() { Token.Token_Id=END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Token.Unget_Token=false; } else @@ -2801,46 +2957,47 @@ void Parser::init_sym_tables() for (i = 0; Reserved_Words[i].Token_Name != NULL; i++) { - Add_Symbol(0,Reserved_Words[i].Token_Name,Reserved_Words[i].Token_Number); + Add_Symbol(SYM_TABLE_RESERVED,Reserved_Words[i].Token_Name,Reserved_Words[i].Token_Number); } Add_Sym_Table(); } -void Parser::Add_Sym_Table() +Parser::SYM_TABLE *Parser::Create_Sym_Table (bool copyNames) { - int i; - - SYM_TABLE *New; + SYM_TABLE *New = reinterpret_cast(POV_MALLOC(sizeof(SYM_TABLE),"symbol table")); + New->namesAreCopies = copyNames; - if ((++Table_Index)==MAX_NUMBER_OF_TABLES) + for (int i = 0; i < SYM_TABLE_SIZE; i++) { - Table_Index--; - Error("Too many nested symbol tables"); + New->Table[i] = NULL; } - Tables[Table_Index]=New=reinterpret_cast(POV_MALLOC(sizeof(SYM_TABLE),"symbol table")); + return New; +} - for (i = 0; i < SYM_TABLE_SIZE; i++) +void Parser::Add_Sym_Table() +{ + if ((++Table_Index)==MAX_NUMBER_OF_TABLES) { - New->Table[i] = NULL; + Table_Index--; + Error("Too many nested symbol tables"); } + Tables[Table_Index] = Create_Sym_Table (Table_Index != 0); } -void Parser::Destroy_Table(int index) +void Parser::Destroy_Sym_Table (Parser::SYM_TABLE *Table) { - int i; - SYM_TABLE *Table = Tables[index]; SYM_ENTRY *Entry; - for(i = SYM_TABLE_SIZE - 1; i >= 0; i--) + for(int i = SYM_TABLE_SIZE - 1; i >= 0; i--) { Entry = Table->Table[i]; while(Entry) { - Entry = Destroy_Entry(index, Entry); + Entry = Destroy_Entry (Entry, Table->namesAreCopies); } Table->Table[i] = NULL; @@ -2850,7 +3007,33 @@ void Parser::Destroy_Table(int index) } -SYM_ENTRY *Parser::Create_Entry (int Index,const char *Name,TOKEN Number) +void Parser::Destroy_Table(int index) +{ + Destroy_Sym_Table (Tables[index]); +} + +Parser::SYM_TABLE *Parser::Copy_Sym_Table (const Parser::SYM_TABLE *table) +{ + SYM_TABLE *newTable = Create_Sym_Table (true); + SYM_ENTRY *Entry, *newEntry; + + for(int i = SYM_TABLE_SIZE - 1; i >= 0; i--) + { + Entry = table->Table[i]; + + while(Entry) + { + newEntry = Copy_Entry (Entry); + newEntry->next = newTable->Table[i]; + newTable->Table[i] = newEntry; + Entry = Entry->next; + } + } + + return newTable; +} + +SYM_ENTRY *Parser::Create_Entry (const char *Name, TOKEN Number, bool copyName) { SYM_ENTRY *New; @@ -2863,7 +3046,7 @@ SYM_ENTRY *Parser::Create_Entry (int Index,const char *Name,TOKEN Number) New->deprecatedShown = false; New->Deprecation_Message = NULL; New->ref_count = 1; - if (Index != 0) + if (copyName) New->Token_Name = POV_STRDUP(Name); else New->Token_Name = const_cast(Name); @@ -2871,6 +3054,24 @@ SYM_ENTRY *Parser::Create_Entry (int Index,const char *Name,TOKEN Number) return(New); } +SYM_ENTRY *Parser::Copy_Entry (const SYM_ENTRY *oldEntry) +{ + SYM_ENTRY *newEntry; + + newEntry = reinterpret_cast(POV_MALLOC(sizeof(SYM_ENTRY), "symbol table entry")); + + newEntry->Token_Number = oldEntry->Token_Number; + newEntry->Data = Copy_Identifier (oldEntry->Data, oldEntry->Token_Number); + newEntry->deprecated = false; + newEntry->deprecatedOnce = false; + newEntry->deprecatedShown = false; + newEntry->Deprecation_Message = NULL; + newEntry->ref_count = 1; + newEntry->Token_Name = POV_STRDUP (oldEntry->Token_Name); + + return newEntry; +} + void Parser::Acquire_Entry_Reference (SYM_ENTRY *Entry) { if (Entry == NULL) @@ -2880,7 +3081,7 @@ void Parser::Acquire_Entry_Reference (SYM_ENTRY *Entry) Entry->ref_count ++; } -void Parser::Release_Entry_Reference (int Index, SYM_ENTRY *Entry) +void Parser::Release_Entry_Reference (SYM_TABLE *table, SYM_ENTRY *Entry) { if (Entry == NULL) return; @@ -2890,7 +3091,7 @@ void Parser::Release_Entry_Reference (int Index, SYM_ENTRY *Entry) if (Entry->ref_count == 0) { - if(Index != 0) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap + if (table->namesAreCopies) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap { POV_FREE(Entry->Token_Name); Destroy_Ident_Data (Entry->Data, Entry->Token_Number); // TODO - shouldn't this be outside the if() block? @@ -2902,7 +3103,7 @@ void Parser::Release_Entry_Reference (int Index, SYM_ENTRY *Entry) } } -SYM_ENTRY *Parser::Destroy_Entry (int Index, SYM_ENTRY *Entry) +SYM_ENTRY *Parser::Destroy_Entry (SYM_ENTRY *Entry, bool destroyName) { SYM_ENTRY *Next; @@ -2919,7 +3120,7 @@ SYM_ENTRY *Parser::Destroy_Entry (int Index, SYM_ENTRY *Entry) if (Entry->ref_count == 0) { - if(Index != 0) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap + if (destroyName) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap { POV_FREE(Entry->Token_Name); Destroy_Ident_Data (Entry->Data, Entry->Token_Number); // TODO - shouldn't this be outside the if() block? @@ -2934,33 +3135,46 @@ SYM_ENTRY *Parser::Destroy_Entry (int Index, SYM_ENTRY *Entry) } -void Parser::Add_Entry (int Index,SYM_ENTRY *Table_Entry) +void Parser::Add_Entry (SYM_TABLE *table, SYM_ENTRY *Table_Entry) { int i = get_hash_value(Table_Entry->Token_Name); - Table_Entry->next = Tables[Index]->Table[i]; - Tables[Index]->Table[i] = Table_Entry; + Table_Entry->next = table->Table[i]; + table->Table[i] = Table_Entry; +} + +void Parser::Add_Entry (int Index,SYM_ENTRY *Table_Entry) +{ + Add_Entry (Tables[Index], Table_Entry); } +SYM_ENTRY *Parser::Add_Symbol (SYM_TABLE *table, const char *Name, TOKEN Number) +{ + SYM_ENTRY *New; + + New = Create_Entry (Name, Number, table->namesAreCopies); + Add_Entry (table, New); + + return(New); +} + SYM_ENTRY *Parser::Add_Symbol (int Index,const char *Name,TOKEN Number) { SYM_ENTRY *New; - New = Create_Entry (Index,Name,Number); + New = Create_Entry (Name, Number, (Index != SYM_TABLE_RESERVED)); Add_Entry(Index,New); return(New); } -SYM_ENTRY *Parser::Find_Symbol (int Index, const char *Name) +SYM_ENTRY *Parser::Find_Symbol (const SYM_TABLE *table, const char *Name, int hash) { SYM_ENTRY *Entry; - int i = get_hash_value(Name); - - Entry = Tables[Index]->Table[i]; + Entry = table->Table[hash]; while (Entry) { @@ -2975,13 +3189,23 @@ SYM_ENTRY *Parser::Find_Symbol (int Index, const char *Name) return(Entry); } +SYM_ENTRY *Parser::Find_Symbol (const SYM_TABLE *table, const char *name) +{ + return Find_Symbol (table, name, get_hash_value (name)); +} + +SYM_ENTRY *Parser::Find_Symbol (int index, const char *name) +{ + return Find_Symbol (Tables[index], name, get_hash_value(name)); +} SYM_ENTRY *Parser::Find_Symbol (const char *name) { SYM_ENTRY *entry; + int hash = get_hash_value (name); for (int index = Table_Index; index > 0; --index) { - entry = Find_Symbol (index, name); + entry = Find_Symbol (Tables[index], name, hash); if (entry) return entry; } @@ -2989,7 +3213,7 @@ SYM_ENTRY *Parser::Find_Symbol (const char *name) } -void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, void **DataPtr, int ttype) +void Parser::Remove_Symbol (SYM_TABLE *table, const char *Name, bool is_array_elem, void **DataPtr, int ttype) { if(is_array_elem == true) { @@ -3013,7 +3237,7 @@ void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, voi int i = get_hash_value(Name); - EntryPtr = &(Tables[Index]->Table[i]); + EntryPtr = &(table->Table[i]); Entry = *EntryPtr; while (Entry) @@ -3021,7 +3245,7 @@ void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, voi if (strcmp(Name, Entry->Token_Name) == 0) { *EntryPtr = Entry->next; - Destroy_Entry(Index, Entry); + Destroy_Entry (Entry, table->namesAreCopies); return; } @@ -3033,6 +3257,11 @@ void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, voi } } +void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, void **DataPtr, int ttype) +{ + return Remove_Symbol (Tables[Index], Name, is_array_elem, DataPtr, ttype); +} + void Parser::Check_Macro_Vers(void) { if (sceneData->EffectiveLanguageVersion() < 310) @@ -3053,16 +3282,14 @@ Parser::Macro *Parser::Parse_Macro() Ok_To_Declare = false; - EXPECT + EXPECT_ONE CASE (IDENTIFIER_TOKEN) - Table_Entry = Add_Symbol (1,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN); - EXIT + Table_Entry = Add_Symbol (SYM_TABLE_GLOBAL,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN); END_CASE CASE (MACRO_ID_TOKEN) - Remove_Symbol(1,Token.Token_String,false,NULL,0); - Table_Entry = Add_Symbol (1,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN); - EXIT + Remove_Symbol(SYM_TABLE_GLOBAL,Token.Token_String,false,NULL,0); + Table_Entry = Add_Symbol (SYM_TABLE_GLOBAL,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN); END_CASE OTHERWISE @@ -3076,14 +3303,12 @@ Parser::Macro *Parser::Parse_Macro() New->Macro_Filename = NULL; - EXPECT + EXPECT_ONE CASE (LEFT_PAREN_TOKEN ) - EXIT END_CASE CASE (TEMPORARY_MACRO_ID_TOKEN) Error( "Can't invoke a macro while declaring its parameters"); END_CASE - OTHERWISE Expectation_Error ("identifier"); END_CASE @@ -3098,13 +3323,13 @@ Parser::Macro *Parser::Parse_Macro() CASE3 (MACRO_ID_TOKEN, IDENTIFIER_TOKEN, PARAMETER_ID_TOKEN) CASE3 (FILE_ID_TOKEN, FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN) // These have to match Parse_Declare in parse.cpp! [trf] - CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) + CASE4 (NORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN) CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN) CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN) CASE4 (DENSITY_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_MAP_ID_TOKEN, UV_ID_TOKEN) CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN) - CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN) + CASE3 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN, DICTIONARY_ID_TOKEN) newParameter.name = POV_STRDUP(Token.Token_String); New->parameters.push_back(newParameter); Parse_Comma(); @@ -3194,7 +3419,7 @@ void Parser::Invoke_Macro() for (i=0; iparameters.size(); i++) { bool finalParameter = (i == PMac->parameters.size()-1); - Table_Entries[i]=Create_Entry(1,PMac->parameters[i].name,IDENTIFIER_TOKEN); + Table_Entries[i] = Create_Entry (PMac->parameters[i].name, IDENTIFIER_TOKEN, true); if (!Parse_RValue(IDENTIFIER_TOKEN, &(Table_Entries[i]->Token_Number), &(Table_Entries[i]->Data), NULL, true, false, true, true, true, Local_Index)) { EXPECT_ONE @@ -3226,7 +3451,7 @@ void Parser::Invoke_Macro() END_CASE END_EXPECT - Destroy_Entry(1,Table_Entries[i]); + Destroy_Entry (Table_Entries[i], true); Table_Entries[i] = NULL; } properlyDelimited = Parse_Comma(); @@ -3296,6 +3521,8 @@ void Parser::Invoke_Macro() Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Check_Macro_Vers(); @@ -3359,7 +3586,8 @@ Parser::POV_ARRAY *Parser::Parse_Array_Declare (void) POV_ARRAY *New; int i,j; - New=reinterpret_cast(POV_MALLOC(sizeof(POV_ARRAY),"array")); + New = new POV_ARRAY; + New->resizable = false; i=0; j=1; @@ -3387,14 +3615,19 @@ Parser::POV_ARRAY *Parser::Parse_Array_Declare (void) END_CASE END_EXPECT - if ( i < 1 ) { - Error( "An array declaration must have at least one dimension"); + if (i == 0) { + // new syntax: Dynamically sized one-dimensional array + i = 1; + New->Sizes[0] = 0; + New->resizable = true; + New->Dims = 0; } - - New->Dims = i-1; - New->Total = j; - New->Type = EMPTY_ARRAY_TOKEN; - New->DataPtrs = reinterpret_cast(POV_MALLOC(sizeof(void *)*j,"array")); + else + { + New->Dims = i-1; + New->DataPtrs.resize (j); + } + New->Type = EMPTY_ARRAY_TOKEN; j = 1; @@ -3404,26 +3637,83 @@ Parser::POV_ARRAY *Parser::Parse_Array_Declare (void) j *= New->Sizes[i]; } - for (i=0; iTotal; i++) + for (i=0; iDataPtrs.size(); i++) { - New->DataPtrs[i] = NULL; + POV_PARSER_ASSERT (New->DataPtrs[i] == NULL); } - EXPECT + EXPECT_ONE CASE2(LEFT_CURLY_TOKEN, OPTIONAL_TOKEN) UNGET Parse_Initalizer(0,0,New); - EXIT END_CASE OTHERWISE UNGET - EXIT END_CASE END_EXPECT Ok_To_Declare = true; return(New); +}; + + +Parser::SYM_TABLE *Parser::Parse_Dictionary_Declare() +{ + SYM_TABLE *newDictionary; + SYM_ENTRY *newEntry; + bool oldParseRawIdentifiers; + char *dictIndex; + + newDictionary = Create_Sym_Table (true); + + // TODO REVIEW - maybe we need `Ok_To_Declare = false`? + + if (!Parse_Begin (false)) + return newDictionary; + + EXPECT + CASE (PERIOD_TOKEN) + oldParseRawIdentifiers = parseRawIdentifiers; + parseRawIdentifiers = true; + Get_Token(); + parseRawIdentifiers = oldParseRawIdentifiers; + if (Token.Token_Id != IDENTIFIER_TOKEN) + Expectation_Error ("dictionary element identifier"); + newEntry = Add_Symbol (newDictionary, Token.Token_String, IDENTIFIER_TOKEN); + + GET (COLON_TOKEN); + + if (!Parse_RValue (IDENTIFIER_TOKEN, &(newEntry->Token_Number), &(newEntry->Data), newEntry, false, false, true, true, false, MAX_NUMBER_OF_TABLES)) + Expectation_Error("RValue"); + + Parse_Comma(); + END_CASE + + CASE (LEFT_SQUARE_TOKEN) + dictIndex = Parse_C_String(); + newEntry = Add_Symbol (newDictionary, dictIndex, IDENTIFIER_TOKEN); + POV_PARSER_ASSERT (newDictionary->namesAreCopies); + POV_FREE (dictIndex); + + GET (RIGHT_SQUARE_TOKEN); + GET (COLON_TOKEN); + + if (!Parse_RValue (IDENTIFIER_TOKEN, &(newEntry->Token_Number), &(newEntry->Data), newEntry, false, false, true, true, false, MAX_NUMBER_OF_TABLES)) + Expectation_Error("RValue"); + + Parse_Comma(); + END_CASE + + OTHERWISE + UNGET + EXIT + END_CASE + END_EXPECT + + Parse_End(); + + return newDictionary; }; @@ -3453,9 +3743,17 @@ void Parser::Parse_Initalizer (int Sub, int Base, POV_ARRAY *a) else { bool properlyDelimited = true; - for(i=0; i < a->Sizes[Sub]; i++) + bool finalParameter = (!a->resizable && (a->Sizes[Sub] == 0)); + for(i=0; !finalParameter; i++) { - bool finalParameter = (i == a->Sizes[Sub]-1); + if (a->resizable) + { + a->DataPtrs.push_back (NULL); + a->Sizes[Sub] = a->DataPtrs.size(); + } + else + finalParameter = (i == (a->Sizes[Sub]-1)); + if (!Parse_RValue (a->Type, &(a->Type), &(a->DataPtrs[Base+i]), NULL, false, false, true, false, true, MAX_NUMBER_OF_TABLES)) { EXPECT_ONE @@ -3466,12 +3764,22 @@ void Parser::Parse_Initalizer (int Sub, int Base, POV_ARRAY *a) END_CASE CASE (RIGHT_CURLY_TOKEN) - if (!(finalParameter && properlyDelimited)) - // the parameter list was closed prematurely - Error("Expected %d initializers but only %d found.",a->Sizes[Sub],i); - // the parameter was left empty - if(!optional) - Error("Cannot omit elements of non-optional array initializer."); + if (a->resizable) + { + finalParameter = true; + POV_PARSER_ASSERT (a->DataPtrs.back() == NULL); + a->DataPtrs.pop_back(); + a->Sizes[Sub] = a->DataPtrs.size(); + } + else + { + if (!(finalParameter && properlyDelimited)) + // the parameter list was closed prematurely + Error("Expected %d initializers but only %d found.",a->Sizes[Sub],i); + // the parameter was left empty + if(!optional) + Error("Cannot omit elements of non-optional array initializer."); + } UNGET END_CASE @@ -3507,16 +3815,17 @@ void Parser::Parse_Fopen(void) New=reinterpret_cast(POV_MALLOC(sizeof(DATA_FILE),"user file")); New->In_File=NULL; New->Out_File=NULL; + New->fopenCompleted = false; GET(IDENTIFIER_TOKEN) - Entry = Add_Symbol (1,Token.Token_String,FILE_ID_TOKEN); + Entry = Add_Symbol (SYM_TABLE_GLOBAL,Token.Token_String,FILE_ID_TOKEN); Entry->Data=reinterpret_cast(New); asciiFileName = Parse_C_String(true); fileName = ASCIItoUCS2String(asciiFileName); POV_FREE(asciiFileName); - EXPECT + EXPECT_ONE CASE(READ_TOKEN) New->R_Flag = true; rfile = Locate_File(fileName.c_str(), POV_File_Text_User, ign, true); @@ -3527,7 +3836,6 @@ void Parser::Parse_Fopen(void) if(New->In_File == NULL) Error ("Cannot open user file %s (read).", UCS2toASCIIString(fileName).c_str()); - EXIT END_CASE CASE(WRITE_TOKEN) @@ -3540,7 +3848,6 @@ void Parser::Parse_Fopen(void) if(New->Out_File == NULL) Error ("Cannot open user file %s (write).", UCS2toASCIIString(fileName).c_str()); - EXIT END_CASE CASE(APPEND_TOKEN) @@ -3553,22 +3860,25 @@ void Parser::Parse_Fopen(void) if(New->Out_File == NULL) Error ("Cannot open user file %s (append).", UCS2toASCIIString(fileName).c_str()); - EXIT END_CASE OTHERWISE Expectation_Error("read or write"); END_CASE END_EXPECT + + New->fopenCompleted = true; } void Parser::Parse_Fclose(void) { DATA_FILE *Data; - EXPECT + EXPECT_ONE CASE(FILE_ID_TOKEN) Data=reinterpret_cast(Token.Data); + if (!Data->fopenCompleted) + Error ("#fopen statement incomplete."); if(Data->In_File != NULL) delete Data->In_File; if(Data->Out_File != NULL) @@ -3576,12 +3886,14 @@ void Parser::Parse_Fclose(void) Got_EOF=false; Data->In_File = NULL; Data->Out_File = NULL; - Remove_Symbol (1,Token.Token_String,false,NULL,0); - EXIT + Remove_Symbol (SYM_TABLE_GLOBAL,Token.Token_String,false,NULL,0); END_CASE OTHERWISE - EXIT + // To allow `#fclose` to be invoked on an already-closed file, + // we need to accept IDENTIFIER_TOKEN, but also any *_ID_TOKEN + // since it may be used at a less local level. + // (Caveat: This allows to accidentally close a file at a less local level.) END_CASE END_EXPECT } @@ -3598,6 +3910,8 @@ void Parser::Parse_Read() GET(FILE_ID_TOKEN) User_File=reinterpret_cast(Token.Data); File_Id=POV_STRDUP(Token.Token_String); + if (!User_File->fopenCompleted) + Error ("#fopen statement incomplete."); if(User_File->In_File == NULL) Error("Cannot read from file %s because the file is open for writing only.", UCS2toASCIIString(UCS2String(User_File->Out_File->name())).c_str()); @@ -3609,9 +3923,11 @@ void Parser::Parse_Read() CASE (IDENTIFIER_TOKEN) if (!End_File) { - Temp_Entry = Add_Symbol (1,Token.Token_String,IDENTIFIER_TOKEN); + Temp_Entry = Add_Symbol (SYM_TABLE_GLOBAL,Token.Token_String,IDENTIFIER_TOKEN); End_File=Parse_Read_Value (User_File,Token.Token_Id, &(Temp_Entry->Token_Number), &(Temp_Entry->Data)); Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Parse_Comma(); /* Scene file comma between 2 idents */ } END_CASE @@ -3621,6 +3937,8 @@ void Parser::Parse_Read() { End_File=Parse_Read_Value (User_File,Token.Token_Id,Token.NumberPtr,Token.DataPtr); Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; Parse_Comma(); /* Scene file comma between 2 idents */ } END_CASE @@ -3666,7 +3984,7 @@ void Parser::Parse_Read() delete User_File->In_File; Got_EOF=false; User_File->In_File = NULL; - Remove_Symbol (1,File_Id,false,NULL,0); + Remove_Symbol (SYM_TABLE_GLOBAL,File_Id,false,NULL,0); } POV_FREE(File_Id); } @@ -3690,7 +4008,7 @@ int Parser::Parse_Read_Value(DATA_FILE *User_File,int Previous,int *NumberPtr,vo try { - EXPECT + EXPECT_ONE CASE3 (PLUS_TOKEN,DASH_TOKEN,FLOAT_FUNCT_TOKEN) UNGET Val=Parse_Signed_Float(); @@ -3699,7 +4017,6 @@ int Parser::Parse_Read_Value(DATA_FILE *User_File,int Previous,int *NumberPtr,vo *DataPtr = reinterpret_cast(Create_Float()); *(reinterpret_cast(*DataPtr)) = Val; Parse_Comma(); /* data file comma between 2 data items */ - EXIT END_CASE CASE (LEFT_ANGLE_TOKEN) @@ -3756,7 +4073,6 @@ int Parser::Parse_Read_Value(DATA_FILE *User_File,int Previous,int *NumberPtr,vo } Parse_Comma(); // data file comma between 2 data items - EXIT END_CASE CASE(STRING_LITERAL_TOKEN) @@ -3764,11 +4080,9 @@ int Parser::Parse_Read_Value(DATA_FILE *User_File,int Previous,int *NumberPtr,vo Test_Redefine(Previous,NumberPtr,*DataPtr); *DataPtr = String_Literal_To_UCS2(Token.Token_String, false); Parse_Comma(); // data file comma between 2 data items - EXIT END_CASE CASE (END_OF_FILE_TOKEN) - EXIT END_CASE OTHERWISE @@ -3809,6 +4123,8 @@ void Parser::Parse_Write(void) GET(FILE_ID_TOKEN) User_File=reinterpret_cast(Token.Data); + if (!User_File->fopenCompleted) + Error ("#fopen statement incomplete."); if(User_File->Out_File == NULL) Error("Cannot write to file %s because the file is open for reading only.", UCS2toASCIIString(UCS2String(User_File->In_File->name())).c_str()); @@ -3818,20 +4134,20 @@ void Parser::Parse_Write(void) CASE5 (SINT8_TOKEN,SINT16BE_TOKEN,SINT16LE_TOKEN,SINT32BE_TOKEN,SINT32LE_TOKEN) CASE3 (UINT8_TOKEN,UINT16BE_TOKEN,UINT16LE_TOKEN) { - signed long val_min; - signed long val_max; + POV_INT32 val_min; + POV_INT32 val_max; int num_bytes; bool big_endian = false; switch (Token.Token_Id) { - case SINT8_TOKEN: val_min = -128; val_max = 127; num_bytes = 1; break; // -2^7 to 2^7-1 - case UINT8_TOKEN: val_min = 0; val_max = 255; num_bytes = 1; break; // 0 to 2^8-1 - case SINT16BE_TOKEN: big_endian = true; // FALLTHROUGH - case SINT16LE_TOKEN: val_min = -32768; val_max = 32767; num_bytes = 2; break; // -2^15 to 2^15-1 - case UINT16BE_TOKEN: big_endian = true; // FALLTHROUGH - case UINT16LE_TOKEN: val_min = 0; val_max = 65535; num_bytes = 2; break; // 0 to 2^16-1 - case SINT32BE_TOKEN: big_endian = true; // FALLTHROUGH - case SINT32LE_TOKEN: val_min = (-2147483647-1); val_max = 2147483647; num_bytes = 4; break; // -2^31 to 2^31-1 (using unconventional notation to avoid a warning with some compiler) + case SINT8_TOKEN: val_min = SIGNED8_MIN; val_max = SIGNED8_MAX; num_bytes = 1; break; + case UINT8_TOKEN: val_min = 0; val_max = UNSIGNED8_MAX; num_bytes = 1; break; + case SINT16BE_TOKEN: val_min = SIGNED16_MIN; val_max = SIGNED16_MAX; num_bytes = 2; big_endian = true; break; + case SINT16LE_TOKEN: val_min = SIGNED16_MIN; val_max = SIGNED16_MAX; num_bytes = 2; big_endian = false; break; + case UINT16BE_TOKEN: val_min = 0; val_max = UNSIGNED16_MAX; num_bytes = 2; big_endian = true; break; + case UINT16LE_TOKEN: val_min = 0; val_max = UNSIGNED16_MAX; num_bytes = 2; big_endian = false; break; + case SINT32BE_TOKEN: val_min = SIGNED32_MIN; val_max = SIGNED32_MAX; num_bytes = 4; big_endian = true; break; + case SINT32LE_TOKEN: val_min = SIGNED32_MIN; val_max = SIGNED32_MAX; num_bytes = 4; big_endian = false; break; } EXPECT CASE_VECTOR @@ -4010,6 +4326,8 @@ int Parser::Parse_For_Param (char** IdentifierPtr, DBL* EndPtr, DBL* StepPtr) EXPECT_ONE CASE (IDENTIFIER_TOKEN) POV_PARSER_ASSERT(!Token.is_array_elem); + if (Token.is_dictionary_elem) + Error("#for loop variable must not be an array or dictionary element"); Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN); Token.NumberPtr = &(Temp_Entry->Token_Number); Token.DataPtr = &(Temp_Entry->Data); @@ -4017,22 +4335,22 @@ int Parser::Parse_For_Param (char** IdentifierPtr, DBL* EndPtr, DBL* StepPtr) END_CASE CASE2 (FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN) - if (Token.is_array_elem) - Error("#for loop variable must not be an array element"); + if (Token.is_array_elem || Token.is_dictionary_elem) + Error("#for loop variable must not be an array or dictionary element"); Error("Redeclaring functions is not allowed - #undef the function first!"); END_CASE // These have to match Parse_Declare in parse.cpp! - CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) + CASE4 (NORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN) CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN) CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN) CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN) CASE4 (DENSITY_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_MAP_ID_TOKEN, UV_ID_TOKEN) CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN) - CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN) - if (Token.is_array_elem) - Error("#for loop variable must not be an array element"); - if (Token.Table_Index != Table_Index) + CASE3 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN, DICTIONARY_ID_TOKEN) + if (Token.is_array_elem || Token.is_dictionary_elem) + Error("#for loop variable must not be an array or dictionary element"); + if (Token.context != Table_Index) { Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN); Token.NumberPtr = &(Temp_Entry->Token_Number); @@ -4046,19 +4364,19 @@ int Parser::Parse_For_Param (char** IdentifierPtr, DBL* EndPtr, DBL* StepPtr) END_CASE CASE (EMPTY_ARRAY_TOKEN) - POV_PARSER_ASSERT(Token.is_array_elem); + POV_PARSER_ASSERT (Token.is_array_elem && !Token.is_mixed_array_elem); Error("#for loop variable must not be an array element"); Previous = Token.Token_Id; END_CASE CASE2 (VECTOR_FUNCT_TOKEN, FLOAT_FUNCT_TOKEN) - if (Token.is_array_elem) - Error("#for loop variable must not be an array element"); + if (Token.is_array_elem || Token.is_dictionary_elem) + Error("#for loop variable must not be an array or dictionary element"); switch(Token.Function_Id) { case VECTOR_ID_TOKEN: case FLOAT_ID_TOKEN: - if (Token.Table_Index != Table_Index) + if (Token.context != Table_Index) { Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN); Token.NumberPtr = &(Temp_Entry->Token_Number); @@ -4078,8 +4396,8 @@ int Parser::Parse_For_Param (char** IdentifierPtr, DBL* EndPtr, DBL* StepPtr) END_CASE OTHERWISE - if (Token.is_array_elem) - Error("#for loop variable must not be an array element"); + if (Token.is_array_elem || Token.is_dictionary_elem) + Error("#for loop variable must not be an array or dictionary element"); Parse_Error(IDENTIFIER_TOKEN); END_CASE END_EXPECT @@ -4161,6 +4479,8 @@ void Parser::IncludeHeader(const UCS2String& formalFileName) Token.Token_Id = END_OF_FILE_TOKEN; Token.is_array_elem = false; + Token.is_mixed_array_elem = false; + Token.is_dictionary_elem = false; } } diff --git a/source/parser/reservedwords.cpp b/source/parser/reservedwords.cpp index c9ef73beb..43c916669 100644 --- a/source/parser/reservedwords.cpp +++ b/source/parser/reservedwords.cpp @@ -46,7 +46,7 @@ namespace pov /* * Here are the reserved words. If you need to add new words, - * be sure to declare them in reswords.h + * be sure to declare them in reservedwords.h */ const RESERVED_WORD Reserved_Words[] = { @@ -179,6 +179,7 @@ const RESERVED_WORD Reserved_Words[] = { { DENTS_TOKEN, "dents" }, { DEPRECATED_TOKEN, "deprecated" }, { DF3_TOKEN, "df3" }, + { DICTIONARY_TOKEN, "dictionary" }, { DIFFERENCE_TOKEN, "difference" }, { DIFFUSE_TOKEN, "diffuse" }, { DIMENSION_SIZE_TOKEN, "dimension_size" }, @@ -259,9 +260,9 @@ const RESERVED_WORD Reserved_Words[] = { { HOLLOW_TOKEN, "hollow" }, { HYPERCOMPLEX_TOKEN, "hypercomplex" }, + { IF_TOKEN, "if" }, { IFDEF_TOKEN, "ifdef" }, { IFF_TOKEN, "iff" }, - { IF_TOKEN, "if" }, { IFNDEF_TOKEN, "ifndef" }, { IMAGE_MAP_TOKEN, "image_map" }, { IMAGE_PATTERN_TOKEN, "image_pattern" }, @@ -341,13 +342,14 @@ const RESERVED_WORD Reserved_Words[] = { { NATURAL_SPLINE_TOKEN, "natural_spline" }, { NEAREST_COUNT_TOKEN, "nearest_count" }, - { NOISE_GENERATOR_TOKEN, "noise_generator" }, { NO_TOKEN, "no" }, { NO_BUMP_SCALE_TOKEN, "no_bump_scale" }, { NO_IMAGE_TOKEN, "no_image" }, { NO_RADIOSITY_TOKEN, "no_radiosity" }, { NO_REFLECTION_TOKEN, "no_reflection" }, { NO_SHADOW_TOKEN, "no_shadow" }, + { NOISE_GENERATOR_TOKEN, "noise_generator" }, + { NORMAL_TOKEN, "normal" }, { NORMAL_INDICES_TOKEN, "normal_indices" }, { NORMAL_MAP_TOKEN, "normal_map" }, { NORMAL_VECTORS_TOKEN, "normal_vectors" }, @@ -397,7 +399,7 @@ const RESERVED_WORD Reserved_Words[] = { { POLY_TOKEN, "poly" }, { POLY_WAVE_TOKEN, "poly_wave" }, { POLYGON_TOKEN, "polygon" }, - { POLYNOM_TOKEN, "polynomial" }, + { POLYNOMIAL_TOKEN, "polynomial" }, { POT_TOKEN, "pot" }, { POTENTIAL_TOKEN, "potential" }, { POW_TOKEN, "pow" }, @@ -460,6 +462,7 @@ const RESERVED_WORD Reserved_Words[] = { #if 0 // sred, sgreen and sblue tokens not enabled at present { SGREEN_TOKEN, "sgreen" }, #endif + { SHADOWLESS_TOKEN, "shadowless" }, { SINE_WAVE_TOKEN, "sine_wave" }, { SIN_TOKEN, "sin" }, { SINH_TOKEN, "sinh" }, @@ -516,12 +519,11 @@ const RESERVED_WORD Reserved_Words[] = { { SWITCH_TOKEN, "switch" }, { SYS_TOKEN, "sys" }, - { TANH_TOKEN, "tanh" }, + { T_TOKEN, "t" }, { TAN_TOKEN, "tan" }, + { TANH_TOKEN, "tanh" }, { TARGET_TOKEN, "target" }, { TAU_TOKEN, "tau" }, - - { T_TOKEN, "t" }, { TEXT_TOKEN, "text" }, { TEXTURE_TOKEN, "texture" }, { TEXTURE_LIST_TOKEN, "texture_list" }, @@ -615,12 +617,6 @@ const RESERVED_WORD Reserved_Words[] = { { QUICK_COLOUR_TOKEN, "quick_color" }, { USE_COLOUR_TOKEN, "use_color" }, - //------------------------------------------------------------------------------ - // Misnomers. - - { TNORMAL_TOKEN, "normal" }, - { FILL_LIGHT_TOKEN, "shadowless" }, - //------------------------------------------------------------------------------ // Operators. @@ -633,7 +629,7 @@ const RESERVED_WORD Reserved_Words[] = { { BACK_SLASH_TOKEN, "\\" }, { BAR_TOKEN, "|" }, { COLON_TOKEN, ":" }, - { COMMA_TOKEN, ", " }, // TODO REVIEW - is a reason for the trailing blank? + { COMMA_TOKEN, ", " }, // TODO REVIEW - is there a reason for the trailing blank? { DASH_TOKEN, "-" }, { DOLLAR_TOKEN, "$" }, { EQUALS_TOKEN, "=" }, @@ -645,14 +641,14 @@ const RESERVED_WORD Reserved_Words[] = { { LEFT_PAREN_TOKEN, "(" }, { LEFT_SQUARE_TOKEN, "[" }, { PERCENT_TOKEN, "%" }, - { PERIOD_TOKEN, ". (period)" }, // TODO REVIEW - is a reason for the plaintext? + { PERIOD_TOKEN, ". (period)" }, // TODO REVIEW - is there a reason for the plaintext? { PLUS_TOKEN, "+" }, { QUESTION_TOKEN, "?" }, { REL_GE_TOKEN, ">=" }, { REL_LE_TOKEN, "<=" }, { REL_NE_TOKEN, "!=" }, { RIGHT_ANGLE_TOKEN, ">" }, - { RIGHT_CURLY_TOKEN, " }" }, // TODO REVIEW - is a reason for the leading blank? + { RIGHT_CURLY_TOKEN, "}" }, { RIGHT_PAREN_TOKEN, ")" }, { RIGHT_SQUARE_TOKEN, "]" }, { SEMI_COLON_TOKEN, ";" }, @@ -680,6 +676,7 @@ const RESERVED_WORD Reserved_Words[] = { { COLOUR_MAP_ID_TOKEN, "colour_map identifier" }, { DENSITY_ID_TOKEN, "density identifier" }, { DENSITY_MAP_ID_TOKEN, "density_map identifier" }, + { DICTIONARY_ID_TOKEN, "dictionary identifier" }, { FILE_ID_TOKEN, "file identifier" }, { FINISH_ID_TOKEN, "finish identifier" }, { FLOAT_ID_TOKEN, "float identifier" }, @@ -689,6 +686,7 @@ const RESERVED_WORD Reserved_Words[] = { { MACRO_ID_TOKEN, "macro identifier" }, { MATERIAL_ID_TOKEN, "material identifier" }, { MEDIA_ID_TOKEN, "media identifier" }, + { NORMAL_ID_TOKEN, "normal identifier" }, { NORMAL_MAP_ID_TOKEN, "normal_map identifier" }, { OBJECT_ID_TOKEN, "object identifier" }, { PARAMETER_ID_TOKEN, "parameter identifier" }, @@ -708,8 +706,6 @@ const RESERVED_WORD Reserved_Words[] = { { VECTOR_4D_ID_TOKEN, "4d-vector identifier" }, { VECTOR_ID_TOKEN, "vector identifier" }, - { TNORMAL_ID_TOKEN, "normal identifier" }, - { EMPTY_ARRAY_TOKEN, "empty array" }, { IDENTIFIER_TOKEN, "undeclared identifier" }, @@ -724,7 +720,7 @@ const RESERVED_WORD Reserved_Words[] = { //------------------------------------------------------------------------------ // End of list, marked by NULL token string. - { LAST_TOKEN, NULL } + { TOKEN_COUNT, NULL } }; } // end of pov namespace diff --git a/source/parser/reservedwords.h b/source/parser/reservedwords.h index f11603a30..855b5c49e 100644 --- a/source/parser/reservedwords.h +++ b/source/parser/reservedwords.h @@ -315,6 +315,8 @@ enum TOKEN_IDS DENTS_TOKEN, DEPRECATED_TOKEN, DF3_TOKEN, + DICTIONARY_TOKEN, + DICTIONARY_ID_TOKEN, DIFFERENCE_TOKEN, DIFFUSE_TOKEN, DIRECTION_TOKEN, @@ -354,7 +356,6 @@ enum TOKEN_IDS FALLOFF_ANGLE_TOKEN, FCLOSE_TOKEN, FILE_ID_TOKEN, - FILL_LIGHT_TOKEN, FINISH_TOKEN, FINISH_ID_TOKEN, FISHEYE_TOKEN, @@ -482,6 +483,8 @@ enum TOKEN_IDS NO_REFLECTION_TOKEN, NO_SHADOW_TOKEN, NOISE_GENERATOR_TOKEN, + NORMAL_TOKEN, + NORMAL_ID_TOKEN, NORMAL_INDICES_TOKEN, NORMAL_MAP_TOKEN, NORMAL_MAP_ID_TOKEN, @@ -535,7 +538,7 @@ enum TOKEN_IDS POLY_TOKEN, POLY_WAVE_TOKEN, POLYGON_TOKEN, - POLYNOM_TOKEN, + POLYNOMIAL_TOKEN, POT_TOKEN, POTENTIAL_TOKEN, PPM_TOKEN, @@ -591,6 +594,7 @@ enum TOKEN_IDS SCALLOP_WAVE_TOKEN, SCATTERING_TOKEN, SEMI_COLON_TOKEN, + SHADOWLESS_TOKEN, SINE_WAVE_TOKEN, SINGLE_QUOTE_TOKEN, SINT16BE_TOKEN, @@ -660,8 +664,6 @@ enum TOKEN_IDS TILE2_TOKEN, TILES_TOKEN, TILING_TOKEN, - TNORMAL_TOKEN, - TNORMAL_ID_TOKEN, TOLERANCE_TOKEN, TOROIDAL_TOKEN, TORUS_TOKEN, @@ -720,7 +722,7 @@ enum TOKEN_IDS //------------------------------------------------------------------------------ // End of list. - LAST_TOKEN // Pseudo-Token to count the number of token identifiers. + TOKEN_COUNT // Pseudo-Token to count the number of token identifiers. }; extern const RESERVED_WORD Reserved_Words[]; diff --git a/source/povms/configpovms.h b/source/povms/configpovms.h index a013072ef..8bd810d07 100644 --- a/source/povms/configpovms.h +++ b/source/povms/configpovms.h @@ -41,7 +41,7 @@ #if !defined(__cplusplus) // When compiling as part of the POV-Ray project, povms.c must be compiled as a C++ file, // due to potential C++-isms in the base/configbase.h header included via this file. - #error povms.c must be compiled as a C++ file when used as part of the POV-Ray project. + #error "povms.c must be compiled as a C++ file when used as part of the POV-Ray project." #endif #include "base/configbase.h" diff --git a/source/vm/configvm.h b/source/vm/configvm.h index 82dffc976..a90861526 100644 --- a/source/vm/configvm.h +++ b/source/vm/configvm.h @@ -81,6 +81,52 @@ namespace pov #define SYS_FUNCTION_ENTRY #endif // SYS_FUNCTIONS + +//****************************************************************************** +/// +/// @name Debug Settings. +/// +/// The following settings enable or disable certain debugging aids, such as run-time sanity checks +/// or additional log output. +/// +/// Unless noted otherwise, a non-zero integer will enable the respective debugging aids, while a +/// zero value will disable them. +/// +/// It is recommended that system-specific configurations leave these settings undefined in release +/// builds, in which case they will default to @ref POV_DEBUG unless noted otherwise. +/// +/// @{ + +/// @def POV_VM_DEBUG +/// Enable run-time sanity checks for the VM. +/// +/// Define as non-zero integer to enable, or zero to disable. +/// +#ifndef POV_VM_DEBUG + #define POV_VM_DEBUG POV_DEBUG +#endif + +/// @} +/// +//****************************************************************************** +/// +/// @name Non-Configurable Macros +/// +/// The following macros are configured automatically at compile-time; they cannot be overridden by +/// system-specific configuration. +/// +/// @{ + +#if POV_VM_DEBUG + #define POV_VM_ASSERT(expr) POV_ASSERT_HARD(expr) +#else + #define POV_VM_ASSERT(expr) POV_ASSERT_DISABLE(expr) +#endif + +/// @} +/// +//****************************************************************************** + } #endif // POVRAY_VM_CONFIGVM_H diff --git a/source/vm/fnpovfpu.cpp b/source/vm/fnpovfpu.cpp index 4587f6e1f..f7120a090 100644 --- a/source/vm/fnpovfpu.cpp +++ b/source/vm/fnpovfpu.cpp @@ -1581,7 +1581,7 @@ GenericFunctionContextPtr FunctionVM::CustomFunction::AcquireContext(TraceThread else { pContext = dynamic_cast(pThreadData->functionContextPool.back()); - POV_ASSERT(pContext != NULL); + POV_VM_ASSERT (pContext != NULL); pThreadData->functionContextPool.pop_back(); } return pContext; @@ -1590,24 +1590,30 @@ GenericFunctionContextPtr FunctionVM::CustomFunction::AcquireContext(TraceThread void FunctionVM::CustomFunction::ReleaseContext(GenericFunctionContextPtr pGenericContext) { FPUContext* pContext = dynamic_cast(pGenericContext); - POV_ASSERT(pContext != NULL); - POV_ASSERT(pContext->threaddata != NULL); - pContext->threaddata->functionContextPool.push_back(pContext); + POV_VM_ASSERT (pContext != NULL); + POV_VM_ASSERT (pContext->threaddata != NULL); + pContext->threaddata->functionContextPool.push_back (pContext); } -void FunctionVM::CustomFunction::InitArguments(GenericFunctionContextPtr pContext) +void FunctionVM::CustomFunction::InitArguments(GenericFunctionContextPtr pGenericContext) { - (dynamic_cast(pContext))->nextArgument = 0; + FPUContext* pContext = dynamic_cast(pGenericContext); + POV_VM_ASSERT (pContext != NULL); + pContext->nextArgument = 0; } -void FunctionVM::CustomFunction::PushArgument(GenericFunctionContextPtr pContext, DBL arg) +void FunctionVM::CustomFunction::PushArgument(GenericFunctionContextPtr pGenericContext, DBL arg) { - (dynamic_cast(pContext))->SetLocal((dynamic_cast(pContext))->nextArgument++, arg); + FPUContext* pContext = dynamic_cast(pGenericContext); + POV_VM_ASSERT (pContext != NULL); + pContext->SetLocal (pContext->nextArgument++, arg); } -DBL FunctionVM::CustomFunction::Execute(GenericFunctionContextPtr pContext) +DBL FunctionVM::CustomFunction::Execute(GenericFunctionContextPtr pGenericContext) { - return POVFPU_Run(dynamic_cast(pContext), *mpFn); + FPUContext* pContext = dynamic_cast(pGenericContext); + POV_VM_ASSERT (pContext != NULL); + return POVFPU_Run (pContext, *mpFn); } GenericScalarFunctionPtr FunctionVM::CustomFunction::Clone() const diff --git a/unix/VERSION b/unix/VERSION index bf8649481..ee5ebcb85 100644 --- a/unix/VERSION +++ b/unix/VERSION @@ -1 +1 @@ -3.7.1-alpha.8826150 +3.7.1-alpha.8889454 diff --git a/unix/configure.ac b/unix/configure.ac index ec6e00b59..003335180 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -646,7 +646,7 @@ AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_DECLS([CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID], [], [], [[#include ]] ) -AC_CHECK_TYPES([clockid_t]) +AC_CHECK_TYPES([clockid_t], [], [], [[#include ]]) # getrusage and related AC_CHECK_FUNCS([getrusage]) diff --git a/unix/install.txt b/unix/install.txt index 204835adc..3a905d98e 100644 --- a/unix/install.txt +++ b/unix/install.txt @@ -139,8 +139,18 @@ recommanded to generate a fully-featured POV-Ray executable. 2.3 Compatibility issues ==================== -- Boost version 1.46 has been reported to be unstable on the Raspberry Pi 2. We recommend using Boost version 1.50 on - this platform. +- Boost version 1.46 has been reported to be unstable on the Raspberry Pi 2. + We recommend using Boost version 1.50 on this platform. + +- Clang 3.4 using standard headers from gcc 4.6 is known to fail when using the + default configure settings, reporting errors in a gcc header file named + "math-finite.h" related to an identifier named "__extern_always_inline". Other + version combinations may be affected as well. To work around this issue, use + the configure option "CXXFLAGS=-fno-fast-math". + +- When configured with "--disable-optimiz", linkage may fail in some cases, + reporting undefined references related to "boost::gregorian::greg_month". To + work around this issue, use the configure option "LDFLAGS=-lboost_date_time". ==================================================== diff --git a/unix/povconfig/syspovconfig.h b/unix/povconfig/syspovconfig.h index 3165770bd..038e92a8c 100644 --- a/unix/povconfig/syspovconfig.h +++ b/unix/povconfig/syspovconfig.h @@ -132,7 +132,7 @@ const int NULL=0; inline bool pov_isnan(T x) { volatile T v = x; return (v != x); } #define POV_ISNAN(x) pov_isnan(x) #else - #error Someone must have found an alternative way of identifying NaNs but failed to implement it here. + #error "Someone must have found an alternative way of identifying NaNs but failed to implement it here." #endif #endif @@ -146,7 +146,7 @@ const int NULL=0; inline bool pov_isinf(T x) { volatile T v = std::numeric_limits::max(); return std::fabs(x) > v; } #define POV_ISINF(x) pov_isinf(x) #else - #error Someone must have found an alternative way of identifying infinities but failed to implement it here. + #error "Someone must have found an alternative way of identifying infinities but failed to implement it here." #endif #endif @@ -203,12 +203,12 @@ const int NULL=0; #if defined(_AIX) // IBM AIX detected. // Not officially supported yet; comment-out the following line to try with default POSIX settings. - #error IBM AIX detected, but not explicitly supported yet; proceed at your own risk. + #error "IBM AIX detected, but not explicitly supported yet; proceed at your own risk." #include "syspovconfig_posix.h" #elif defined(__hpux) // Hewlett-Packard HP-UX detected. // Not officially supported yet; comment-out the following line to try with default POSIX settings. - #error Hewlett-Packard HP-UX detected, but not explicitly supported yet; proceed at your own risk. + #error "Hewlett-Packard HP-UX detected, but not explicitly supported yet; proceed at your own risk." #include "syspovconfig_posix.h" #elif defined(__linux__) // GNU/Linux detected. @@ -219,12 +219,12 @@ const int NULL=0; #elif defined(__sun) && defined(__SVR4) // Sun/Oracle Solaris detected. // Not officially supported yet; comment-out the following line to try with default POSIX settings. - #error Sun/Oracle Solaris detected, but not explicitly supported yet; proceed at your own risk. + #error "Sun/Oracle Solaris detected, but not explicitly supported yet; proceed at your own risk." #include "syspovconfig_posix.h" #elif defined(__CYGWIN__) // Cygwin detected. // Not officially supported yet; comment-out the following line to try with default POSIX settings. - #error Cygwin detected, but not explicitly supported yet; proceed at your own risk. + #error "Cygwin detected, but not explicitly supported yet; proceed at your own risk." #include "syspovconfig_posix.h" #elif defined(__unix__) // Some Unix other than the above detected. @@ -234,13 +234,13 @@ const int NULL=0; #include "syspovconfig_bsd.h" #else // Not officially supported yet; comment-out the following line to try with default POSIX settings. - #error Unix detected, but flavor not identified; proceed at your own risk. + #error "Unix detected, but flavor not identified; proceed at your own risk." #include "syspovconfig_posix.h" #endif #else // Doesn't look like a Unix at all. // Comment-out the following line to try with default POSIX settings. - #error No Unix detected; proceed at your own risk. + #error "No Unix detected; proceed at your own risk." #include "syspovconfig_posix.h" #endif diff --git a/unix/povconfig/syspovconfig_bsd.h b/unix/povconfig/syspovconfig_bsd.h index 4cf34b730..63c31f47b 100644 --- a/unix/povconfig/syspovconfig_bsd.h +++ b/unix/povconfig/syspovconfig_bsd.h @@ -47,11 +47,11 @@ #elif defined(_POSIX_V6_ILP32_OFF32) // off_t is 32 bits // Comment-out the following line to proceed anyway. - #error Image size will be limited to approx. 100 Megapixels. Proceed at your own risk. + #error "Image size will be limited to approx. 100 Megapixels. Proceed at your own risk." #define lseek64(handle,offset,whence) lseek(handle,offset,whence) #else // Unable to detect off_t size at compile-time; comment-out the following line to proceed anyway. - #error Image size may be limited to approx. 100 Megapixels. Proceed at your own risk. + #error "Image size may be limited to approx. 100 Megapixels. Proceed at your own risk." #define lseek64(handle,offset,whence) lseek(handle,offset,whence) #endif diff --git a/unix/povconfig/syspovconfig_posix.h b/unix/povconfig/syspovconfig_posix.h index 23059f573..18564edf2 100644 --- a/unix/povconfig/syspovconfig_posix.h +++ b/unix/povconfig/syspovconfig_posix.h @@ -47,11 +47,11 @@ #elif defined(_POSIX_V6_ILP32_OFF32) // off_t is 32 bits // Comment-out the following line to proceed anyway. - #error Image size will be limited to approx. 100 Megapixels. Proceed at your own risk. + #error "Image size will be limited to approx. 100 Megapixels. Proceed at your own risk." #define lseek64(handle,offset,whence) lseek(handle,offset,whence) #else // Unable to detect off_t size at compile-time; comment-out the following line to proceed anyway. - #error Image size may be limited to approx. 100 Megapixels. Proceed at your own risk. + #error "Image size may be limited to approx. 100 Megapixels. Proceed at your own risk." #define lseek64(handle,offset,whence) lseek(handle,offset,whence) #endif diff --git a/vfe/win/console/winconsole.cpp b/vfe/win/console/winconsole.cpp index 4f18d1407..36ec9f86f 100644 --- a/vfe/win/console/winconsole.cpp +++ b/vfe/win/console/winconsole.cpp @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2015 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2016 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 @@ -42,7 +42,7 @@ #include "vfe.h" #ifndef _CONSOLE -#error You must define _CONSOLE in vfe\win\syspovconfig.h prior to building the console version, otherwise you will get link errors. +#error "You must define _CONSOLE in vfe\win\syspovconfig.h prior to building the console version, otherwise you will get link errors." #endif using namespace vfe; diff --git a/windows/povconfig/syspovconfig.h b/windows/povconfig/syspovconfig.h index 57ab36997..0c21b805f 100644 --- a/windows/povconfig/syspovconfig.h +++ b/windows/povconfig/syspovconfig.h @@ -43,11 +43,11 @@ #ifdef BUILDING_AMD64 #if !defined(_M_AMD64) && !defined(_M_X64) - #error you are compiling the x64 project using a 32-bit compiler + #error "you are compiling the x64 project using a 32-bit compiler" #endif #else #if defined(_M_AMD64) || defined(_M_X64) - #error you are compiling the 32-bit project using a 64-bit compiler + #error "you are compiling the 32-bit project using a 64-bit compiler" #endif #endif @@ -113,18 +113,18 @@ using std::tr1::const_pointer_cast; #define ReturnAddress() NULL #if defined(__MINGW32__) /* MinGW GCC */ - #error Currently not supported. + #error "Currently not supported." #include "syspovconfig_mingw32.h" #elif defined(__WATCOMC__) /* Watcom C/C++ C32 */ - #error Currently not supported. + #error "Currently not supported." #include "syspovconfig_watcom.h" #elif defined(__BORLANDC__) /* Borland C/C++ */ - #error Currently not supported. + #error "Currently not supported." #include "syspovconfig_borland.h" #elif defined(_MSC_VER) /* Microsoft and Intel C++ */ #include "syspovconfig_msvc.h" #else - #error unknown compiler configuration + #error "unknown compiler configuration" #endif #ifdef BUILD_SSE2 diff --git a/windows/povconfig/syspovconfig_msvc.h b/windows/povconfig/syspovconfig_msvc.h index 9c7414366..7e591a12c 100644 --- a/windows/povconfig/syspovconfig_msvc.h +++ b/windows/povconfig/syspovconfig_msvc.h @@ -40,7 +40,7 @@ #define POVRAY_WINDOWS_SYSPOVCONFIG_MSVC_H #if _MSC_VER < 1400 - #error minimum Visual C++ version supported is 14.0 (supplied with VS 2005) + #error "minimum Visual C++ version supported is 14.0 (supplied with VS 2005)" #endif #undef TRY_OPTIMIZED_NOISE @@ -63,7 +63,7 @@ #ifdef __INTEL_COMPILER - #error Intel C++ compiler currently not supported. + #error "Intel C++ compiler currently not supported." // Compiling POV-Ray for Windows using the Intel C++ compiler has not been tested for a long time, and the following // settings are probably outdated. You may proceed at your own risk by removing the above line, but be prepared to run // into problems further down the road. @@ -71,7 +71,7 @@ #pragma warning(disable : 1899) /* multicharacter character literal */ #if __INTEL_COMPILER < 1010 - #error minimum Intel C++ version supported is 10.1 + #error "minimum Intel C++ version supported is 10.1" #endif #if __INTEL_COMPILER >= 1000 && __INTEL_COMPILER < 1100 @@ -81,7 +81,7 @@ #define COMPILER_VER ".icl11" #define METADATA_COMPILER_STRING "icl 11" #else - #error Please update syspovconfig_msvc.h to include this version of ICL + #error "Please update syspovconfig_msvc.h to include this version of ICL" #endif #define COMPILER_NAME "Intel C++ Compiler" #define COMPILER_VERSION __INTEL_COMPILER @@ -133,14 +133,14 @@ // MS Visual C++ 2012 (aka 11.0) #define COMPILER_VER ".msvc11" #define METADATA_COMPILER_STRING "msvc 11" - #error Please update syspovconfig_msvc.h to include this version of MSVC + #error "Please update syspovconfig_msvc.h to include this version of MSVC" // The following settings are just guesswork, and have never been tested: #define NEED_INVHYP #elif _MSC_VER >= 1800 && _MSC_VER < 1900 // MS Visual C++ 2013 (aka 12.0) #define COMPILER_VER ".msvc12" #define METADATA_COMPILER_STRING "msvc 12" - #error Please update syspovconfig_msvc.h to include this version of MSVC + #error "Please update syspovconfig_msvc.h to include this version of MSVC" // The following settings are just guesswork, and have never been tested: // (no special settings) // NB: The Microsoft Visual Studio developers seem to have skipped internal version number 13 entirely. @@ -149,7 +149,7 @@ #define COMPILER_VER ".msvc14" #define METADATA_COMPILER_STRING "msvc 14" #else - #error Please update syspovconfig_msvc.h to include this version of MSVC + #error "Please update syspovconfig_msvc.h to include this version of MSVC" #endif #define COMPILER_NAME "Microsoft Visual C++" #define COMPILER_VERSION _MSC_VER @@ -160,7 +160,7 @@ #if defined(_M_X64) #define METADATA_PLATFORM_STRING "x86_64-pc-win" #else - #error Please update msvc.h to include this 64-bit architecture + #error "Please update msvc.h to include this 64-bit architecture" #endif #elif defined _WIN32 #if !defined(METADATA_X86_FPU_STRING) @@ -172,10 +172,10 @@ #elif (_M_IX86_FP == 2) #define METADATA_X86_FPU_STRING "-sse2" #else - #error Please update msvc.h to include this x86 FPU generation + #error "Please update msvc.h to include this x86 FPU generation" #endif #else - #error Please update msvc.h to detect x86 FPU generation for your compiler + #error "Please update msvc.h to detect x86 FPU generation for your compiler" #endif #endif #if defined(_M_IX86) @@ -190,10 +190,10 @@ #elif (_M_IX86 == 700) #define METADATA_PLATFORM_STRING "i786-pc-win" METADATA_X86_FPU_STRING #else - #error Please update msvc.h to include this x86 CPU generation + #error "Please update msvc.h to include this x86 CPU generation" #endif #else - #error Please update msvc.h to include this 32-bit architecture + #error "Please update msvc.h to include this 32-bit architecture" #endif #endif diff --git a/windows/pvedit.cpp b/windows/pvedit.cpp index fa0b22cf1..b27f0af3a 100644 --- a/windows/pvedit.cpp +++ b/windows/pvedit.cpp @@ -263,7 +263,7 @@ char *Get_Reserved_Words (const char *additional_words) int length = 0 ; int i ; - for (i = 0; Reserved_Words[i].Token_Number != LAST_TOKEN; i++) + for (i = 0; Reserved_Words[i].Token_Number != TOKEN_COUNT; i++) { if (!isalpha (Reserved_Words [i].Token_Name [0])) continue ; @@ -279,7 +279,7 @@ char *Get_Reserved_Words (const char *additional_words) strcat (result, "#\n"); char *s = result + strlen (additional_words) + 2; - for (i = 0; Reserved_Words[i].Token_Number != LAST_TOKEN; i++) + for (i = 0; Reserved_Words[i].Token_Number != TOKEN_COUNT; i++) { if (!isalpha (Reserved_Words [i].Token_Name [0])) continue ; diff --git a/windows/pvengine.h b/windows/pvengine.h index fa8d1d6cc..329440a5a 100644 --- a/windows/pvengine.h +++ b/windows/pvengine.h @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. -/// Copyright 1991-2015 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2016 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 @@ -40,16 +40,16 @@ #ifdef BUILDING_AMD64 #if !defined(_M_AMD64) && !defined(_M_X64) - #error you are compiling the x64 project using a 32-bit compiler + #error "you are compiling the x64 project using a 32-bit compiler" #endif #else #if defined(_M_AMD64) || defined(_M_X64) - #error you are compiling the 32-bit project using a 64-bit compiler + #error "you are compiling the 32-bit project using a 64-bit compiler" #endif #endif #ifdef _CONSOLE -#error You are building the GUI platform with _CONSOLE defined (check vfe\win\syspovconfig.h). +#error "You are building the GUI platform with _CONSOLE defined (check vfe\win\syspovconfig.h)." #endif #include