5468 lines
125 KiB
C++
5468 lines
125 KiB
C++
/*******************************************************************************
|
|
* parstxtr.cpp
|
|
*
|
|
* This module parses textures and atmosphere effects.
|
|
*
|
|
* ---------------------------------------------------------------------------
|
|
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
|
|
* Copyright 1991-2013 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
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* POV-Ray is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------------
|
|
* POV-Ray is based on the popular DKB raytracer version 2.12.
|
|
* DKBTrace was originally written by David K. Buck.
|
|
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
|
|
* ---------------------------------------------------------------------------
|
|
* $File: //depot/public/povray/3.x/source/backend/parser/parstxtr.cpp $
|
|
* $Revision: #1 $
|
|
* $Change: 6069 $
|
|
* $DateTime: 2013/11/06 11:59:40 $
|
|
* $Author: chrisc $
|
|
*******************************************************************************/
|
|
|
|
// frame.h must always be the first POV file included (pulls in platform config)
|
|
#include "backend/frame.h"
|
|
#include "backend/parser/parse.h"
|
|
|
|
#include "backend/math/vector.h"
|
|
#include "backend/colour/colour.h"
|
|
#include "backend/interior/interior.h"
|
|
#include "backend/math/matrices.h"
|
|
#include "backend/interior/media.h"
|
|
#include "backend/texture/normal.h"
|
|
#include "backend/texture/pigment.h"
|
|
#include "backend/texture/texture.h"
|
|
#include "backend/shape/isosurf.h"
|
|
#include "backend/vm/fncode.h"
|
|
#include "backend/vm/fnpovfpu.h"
|
|
#include "backend/scene/objects.h"
|
|
#include "base/image/image.h"
|
|
#include "backend/support/imageutil.h"
|
|
#include "backend/support/fileutil.h"
|
|
|
|
#include "lightgrp.h" // TODO
|
|
|
|
#ifdef SYS_IMAGE_HEADER
|
|
#include SYS_IMAGE_HEADER
|
|
#endif
|
|
|
|
// this must be the last file included
|
|
#include "base/povdebug.h"
|
|
|
|
namespace pov
|
|
{
|
|
|
|
/*****************************************************************************
|
|
* Local preprocessor defines
|
|
******************************************************************************/
|
|
|
|
#define ADD_TNORMAL if (Tnormal == NULL) {if ((Default_Texture->Tnormal) != NULL) \
|
|
Tnormal = Copy_Tnormal ((Default_Texture->Tnormal)); else Tnormal = Create_Tnormal ();\
|
|
Texture->Tnormal=Tnormal;};
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Ronald Parker, changes by Thorsten Froehlich
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Make_Pattern_Image(ImageData *image, FUNCTION_PTR fn, int token)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
DBL val = 0;
|
|
FunctionCode *f = sceneData->functionVM->GetFunction(*fn);
|
|
VECTOR point;
|
|
|
|
image->iwidth = image->width;
|
|
image->iheight = image->height;
|
|
if(token == FUNCT_ID_TOKEN)
|
|
{
|
|
image->data =Image::Create(image->iwidth, image->iheight, Image::Gray_Int16);
|
|
|
|
point[Z] = 0;
|
|
|
|
for(i = 0; i < image->iheight; i++)
|
|
{
|
|
point[Y] = ((DBL)i / (image->height - 1));
|
|
|
|
for( j = 0; j < image->iwidth; j++ )
|
|
{
|
|
point[X] = ((DBL)j / (image->width - 1));
|
|
|
|
fnVMContext->SetLocal(X, point[X]);
|
|
fnVMContext->SetLocal(Y, point[Y]);
|
|
fnVMContext->SetLocal(Z, point[Z]);
|
|
|
|
image->data->SetGrayValue(j, i, float(POVFPU_Run(fnVMContext, *fn)));
|
|
}
|
|
}
|
|
}
|
|
else if((token == VECTFUNCT_ID_TOKEN) && (f->return_size == 5))
|
|
{
|
|
image->data =Image::Create(image->iwidth, image->iheight, Image::RGBA_Int16);
|
|
image->data->SetPremultiplied(false); // We're storing the data in non-premultiplied alpha format, as this preserves all the data we're getting from the function.
|
|
|
|
point[Z] = 0;
|
|
|
|
for(i = 0; i < image->iheight; i++)
|
|
{
|
|
point[Y] = ((DBL)i / (image->height - 1));
|
|
|
|
for(j = 0; j < image->iwidth; j++)
|
|
{
|
|
point[X] = ((DBL)j / (image->width - 1));
|
|
|
|
fnVMContext->SetLocal(X + f->return_size, point[X]);
|
|
fnVMContext->SetLocal(Y + f->return_size, point[Y]);
|
|
fnVMContext->SetLocal(Z + f->return_size, point[Z]);
|
|
|
|
(void)POVFPU_Run(fnVMContext, *fn);
|
|
|
|
image->data->SetRGBFTValue(j, i,
|
|
float(fnVMContext->GetLocal(pRED)),
|
|
float(fnVMContext->GetLocal(pGREEN)),
|
|
float(fnVMContext->GetLocal(pBLUE)),
|
|
float(fnVMContext->GetLocal(pFILTER)), // N.B. pFILTER component is currently ignored by SetRGBFTValue (matches 3.6 behavior)
|
|
float(fnVMContext->GetLocal(pTRANSM)));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
Error("Unsupported function type in function image.");
|
|
|
|
Destroy_Function(fn);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
ImageData *Parser::Parse_Image(int Legal, bool GammaCorrect)
|
|
{
|
|
ImageData *image = NULL;
|
|
VECTOR Local_Vector;
|
|
char *Name = NULL;
|
|
int token_id;
|
|
int filetype = NO_FILE;
|
|
UCS2String ign;
|
|
pov::FUNCTION_PTR fnPtr;
|
|
|
|
image = Create_Image();
|
|
|
|
if(Legal & GRAD_FILE)
|
|
{
|
|
EXPECT
|
|
CASE_VECTOR
|
|
Warning(150, "Old style orientation vector or map type not supported. Ignoring value.");
|
|
Parse_Vector(Local_Vector);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
}
|
|
|
|
EXPECT
|
|
CASE (FUNCTION_TOKEN)
|
|
image->width = (SNGL)int(Parse_Float() + 0.5);
|
|
Parse_Comma();
|
|
image->height = (SNGL)int(Parse_Float() + 0.5);
|
|
|
|
Get_Token();
|
|
if(Token.Token_Id != LEFT_CURLY_TOKEN)
|
|
Found_Instead_Error("Missing { after", "expression");
|
|
Unget_Token();
|
|
|
|
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)
|
|
Experimental_Flag |= EF_TIFF;
|
|
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)
|
|
CASE4 (CONCAT_TOKEN,STRUPR_TOKEN,STRLWR_TOKEN,DATETIME_TOKEN)
|
|
{
|
|
UNGET
|
|
Name = Parse_C_String(true);
|
|
UCS2String filename = ASCIItoUCS2String(Name);
|
|
UCS2String ext = GetFileExtension(Path(filename));
|
|
|
|
if (ext.empty() == false)
|
|
{
|
|
filetype = gFile_Type_To_Mask [InferFileTypeFromExt(ext)];
|
|
if (filetype == NO_FILE)
|
|
{
|
|
POV_FREE(Name);
|
|
Error("Could not determine valid image file type from extension.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (sceneData->defaultFileType)
|
|
{
|
|
case kPOVList_FileType_Targa:
|
|
case kPOVList_FileType_CompressedTarga:
|
|
filetype = TGA_FILE;
|
|
break;
|
|
case kPOVList_FileType_PNG:
|
|
filetype = PNG_FILE;
|
|
break;
|
|
case kPOVList_FileType_JPEG:
|
|
filetype = JPEG_FILE;
|
|
break;
|
|
case kPOVList_FileType_PPM:
|
|
filetype = PPM_FILE;
|
|
break;
|
|
case kPOVList_FileType_BMP:
|
|
filetype = BMP_FILE;
|
|
break;
|
|
case kPOVList_FileType_OpenEXR:
|
|
filetype = EXR_FILE;
|
|
break;
|
|
case kPOVList_FileType_RadianceHDR:
|
|
filetype = HDR_FILE;
|
|
break;
|
|
case kPOVList_FileType_System:
|
|
filetype = SYS_FILE;
|
|
break;
|
|
default:
|
|
POV_FREE(Name);
|
|
Error("Could not determine valid input file type from output type.");
|
|
}
|
|
}
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
Expectation_Error("map file spec");
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if(Name != NULL)
|
|
{
|
|
if(!(filetype & Legal))
|
|
Error("File type not supported here.");
|
|
|
|
UCS2String filename = ASCIItoUCS2String(Name);
|
|
Image::ReadOptions options;
|
|
|
|
switch (sceneData->gammaMode)
|
|
{
|
|
case kPOVList_GammaMode_None:
|
|
options.gammacorrect = false;
|
|
options.defaultGamma.reset();
|
|
options.workingGamma.reset();
|
|
break;
|
|
case kPOVList_GammaMode_AssumedGamma36:
|
|
if (GammaCorrect)
|
|
{
|
|
options.gammacorrect = GammaCorrect;
|
|
options.defaultGamma = SimpleGammaCurvePtr(sceneData->workingGamma);
|
|
options.workingGamma = SimpleGammaCurvePtr(sceneData->workingGamma);
|
|
}
|
|
else
|
|
{
|
|
options.gammacorrect = false;
|
|
options.defaultGamma.reset();
|
|
options.workingGamma.reset();
|
|
}
|
|
break;
|
|
case kPOVList_GammaMode_AssumedGamma37:
|
|
case kPOVList_GammaMode_AssumedGamma37Implied:
|
|
if (GammaCorrect)
|
|
{
|
|
options.gammacorrect = GammaCorrect;
|
|
options.defaultGamma.reset();
|
|
options.workingGamma = SimpleGammaCurvePtr(sceneData->workingGamma);
|
|
}
|
|
else
|
|
{
|
|
options.gammacorrect = false;
|
|
options.defaultGamma.reset();
|
|
options.workingGamma.reset();
|
|
}
|
|
break;
|
|
default:
|
|
throw POV_EXCEPTION_STRING("Unknown gamma handling mode in Parse_Image()");
|
|
}
|
|
|
|
EXPECT
|
|
CASE (GAMMA_TOKEN)
|
|
// User wants to override decoding gamma for this particular file; let them have their will.
|
|
options.gammacorrect = true;
|
|
options.gammaOverride = true;
|
|
options.defaultGamma = Parse_Gamma();
|
|
if (GammaCorrect)
|
|
options.workingGamma = SimpleGammaCurvePtr(sceneData->workingGamma);
|
|
else
|
|
options.workingGamma.reset();
|
|
END_CASE
|
|
CASE (PREMULTIPLIED_TOKEN)
|
|
// User wants to override alpha premultiplication setting for this particular file; let them have their will.
|
|
options.premultiplyOverride = true;
|
|
options.premultiply = ((int)Parse_Float() != 0);
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if (options.gammacorrect && !options.gammaOverride && (filetype == PNG_FILE) && (sceneData->EffectiveLanguageVersion() < 370))
|
|
{
|
|
PossibleError("PNG input image default gamma handling has changed for pre POV-Ray 3.7 scenes;\n"
|
|
"results may differ from original intention. See the documentation for more\n"
|
|
"details.");
|
|
}
|
|
|
|
if (!GammaCorrect)
|
|
{
|
|
// context typically implies that gamma correction is not desired (e.g. height_field)
|
|
if (options.gammacorrect && !options.gammaOverride)
|
|
Warning(0, "input image gamma not specified for height_field, bump_map or image_pattern;\n"
|
|
"no gamma adjustment performed on input image; results may differ from intention\n"
|
|
"in rare cases. See the documentation for details.\n"
|
|
"To get rid of this warning, explicitly specify \"gamma 1.0\".");
|
|
}
|
|
|
|
// beta-test feature
|
|
// if we end up keeping vidcap, it will probably get its own filetype.
|
|
// for now, avoid the need to change the SDL by using the sys file type with the below prefix
|
|
if (filetype == SYS_FILE && strncmp(Name, ":vidcap:", 8) == 0)
|
|
{
|
|
#ifdef POV_VIDCAP_IMPL
|
|
image->VidCap = new POV_VIDCAP_IMPL();
|
|
// note the second ':' gets passed since it's the option prefix
|
|
// e.g. ":vidcap:source=/dev/video0:w=640:h=480:fps=5"
|
|
image->data = image->VidCap->Init(Name + 7, options, true);
|
|
Beta_Feature_Flag |= BF_VIDCAP;
|
|
#else
|
|
Error("Beta-test video capture feature not implemented on this platform.");
|
|
#endif
|
|
}
|
|
else
|
|
image->data = Read_Image(this, sceneData, filetype, filename.c_str(), options);
|
|
|
|
if (!options.warnings.empty())
|
|
for (vector<string>::iterator it = options.warnings.begin(); it != options.warnings.end(); it++)
|
|
Warning (0, "%s: %s", Name, it->c_str()) ;
|
|
|
|
POV_FREE(Name);
|
|
}
|
|
|
|
if(image->data == NULL)
|
|
Error("Cannot read image.");
|
|
|
|
image->iwidth = image->data->GetWidth();
|
|
image->iheight = image->data->GetHeight();
|
|
image->width = (SNGL) image->iwidth;
|
|
image->height = (SNGL) image->iheight;
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
SimpleGammaCurvePtr Parser::Parse_Gamma (void)
|
|
{
|
|
SimpleGammaCurvePtr gamma;
|
|
EXPECT
|
|
CASE (COLOUR_KEY_TOKEN)
|
|
if (Token.Function_Id != SRGB_TOKEN)
|
|
{
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
}
|
|
gamma = SRGBGammaCurve::Get();
|
|
EXIT
|
|
END_CASE
|
|
OTHERWISE
|
|
{
|
|
UNGET
|
|
DBL value = Parse_Float();
|
|
if (value <= 0.0)
|
|
Error ("gamma value must be positive.");
|
|
else if ((value < 1.0) && (sceneData->gammaMode != kPOVList_GammaMode_None))
|
|
// (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
|
|
return gamma;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Image_Map (PIGMENT *Pigment)
|
|
{
|
|
int reg;
|
|
ImageData *image;
|
|
|
|
Parse_Begin();
|
|
|
|
image = Parse_Image (IMAGE_FILE, true);
|
|
image->Use = USE_COLOUR; // was true [trf]
|
|
|
|
EXPECT /* Look for image_attribs */
|
|
CASE (ONCE_TOKEN)
|
|
image->Once_Flag=true;
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
image->Interpolation_Type = (int)Parse_Float();
|
|
switch(image->Interpolation_Type)
|
|
{
|
|
case BILINEAR:
|
|
case BICUBIC:
|
|
case NORMALIZED_DIST:
|
|
break;
|
|
|
|
default:
|
|
Error("Invalid interpolate value.");
|
|
break;
|
|
}
|
|
END_CASE
|
|
|
|
CASE (MAP_TYPE_TOKEN)
|
|
image->Map_Type = (int) Parse_Float ();
|
|
switch(image->Map_Type)
|
|
{
|
|
case PLANAR_MAP:
|
|
case SPHERICAL_MAP:
|
|
case CYLINDRICAL_MAP:
|
|
case TORUS_MAP:
|
|
break;
|
|
|
|
default:
|
|
Error("Invalid map_type value.");
|
|
break;
|
|
}
|
|
END_CASE
|
|
|
|
CASE (USE_COLOUR_TOKEN)
|
|
image->Use = USE_COLOUR; // was true [trf]
|
|
END_CASE
|
|
|
|
CASE (USE_INDEX_TOKEN)
|
|
image->Use = USE_NONE; // was false [trf]
|
|
END_CASE
|
|
|
|
CASE (REPEAT_TOKEN)
|
|
UV_VECT Repeat;
|
|
Parse_UV_Vect (Repeat);
|
|
if ((Repeat[0]<=0.0) || (Repeat[1]<=0.0))
|
|
Error("Zero or Negative Image Repeat Vector.");
|
|
image->width = (DBL)image->iwidth * Repeat[0];
|
|
image->height = (DBL)image->iheight * Repeat[1];
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
Parse_UV_Vect (image->Offset);
|
|
image->Offset[U] *= (DBL)-image->iwidth;
|
|
image->Offset[V] *= (DBL)-image->iheight;
|
|
END_CASE
|
|
|
|
CASE (ALPHA_TOKEN)
|
|
Warning(155, "Keyword ALPHA discontinued. Use FILTER instead.");
|
|
// FALLTHROUGH
|
|
|
|
CASE (COLOUR_KEY_TOKEN)
|
|
switch(Token.Function_Id)
|
|
{
|
|
case FILTER_TOKEN:
|
|
EXPECT
|
|
CASE (ALL_TOKEN)
|
|
{
|
|
DBL filter;
|
|
filter = Parse_Float();
|
|
image->AllFilter = filter;
|
|
if (image->data->IsIndexed())
|
|
{
|
|
if (image->data->HasFilterTransmit() == false)
|
|
{
|
|
vector<Image::RGBFTMapEntry> map ;
|
|
image->data->GetColourMap (map) ;
|
|
image->data->SetColourMap (map) ;
|
|
}
|
|
for(reg = 0 ; reg < image->data->GetColourMapSize(); reg++)
|
|
{
|
|
float r, g, b, f, t;
|
|
|
|
image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t);
|
|
image->data->SetRGBFTIndexedValue(reg, r, g, b, filter, t);
|
|
}
|
|
}
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
reg = (int)(Parse_Float() + 0.01);
|
|
if (image->data->IsIndexed() == false)
|
|
Not_With ("filter","non color-mapped image");
|
|
if ((reg < 0) || (reg >= image->data->GetColourMapSize()))
|
|
Error ("FILTER color register value out of range.");
|
|
|
|
Parse_Comma();
|
|
{
|
|
float r, g, b, f, t;
|
|
|
|
if (image->data->HasFilterTransmit() == false)
|
|
{
|
|
vector<Image::RGBFTMapEntry> map ;
|
|
image->data->GetColourMap (map) ;
|
|
image->data->SetColourMap (map) ;
|
|
}
|
|
image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t);
|
|
image->data->SetRGBFTIndexedValue(reg, r, g, b, Parse_Float(), t);
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
END_EXPECT
|
|
Pigment->Flags |= HAS_FILTER;
|
|
break;
|
|
|
|
case TRANSMIT_TOKEN:
|
|
EXPECT
|
|
CASE (ALL_TOKEN)
|
|
{
|
|
DBL transmit;
|
|
transmit = Parse_Float();
|
|
image->AllTransmit = transmit;
|
|
if (image->data->IsIndexed())
|
|
{
|
|
if (image->data->HasFilterTransmit() == false)
|
|
{
|
|
vector<Image::RGBFTMapEntry> map ;
|
|
image->data->GetColourMap (map) ;
|
|
image->data->SetColourMap (map) ;
|
|
}
|
|
for(reg = 0 ; reg < image->data->GetColourMapSize(); reg++)
|
|
{
|
|
float r, g, b, f, t;
|
|
|
|
image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t);
|
|
image->data->SetRGBFTIndexedValue(reg, r, g, b, f, transmit);
|
|
}
|
|
}
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
reg = (int)(Parse_Float() + 0.01);
|
|
if (image->data->IsIndexed() == false)
|
|
Not_With ("transmit","non color-mapped image");
|
|
if ((reg < 0) || (reg >= image->data->GetColourMapSize()))
|
|
Error ("TRANSMIT color register value out of range.");
|
|
|
|
Parse_Comma();
|
|
{
|
|
float r, g, b, f, t;
|
|
|
|
if (image->data->HasFilterTransmit() == false)
|
|
{
|
|
vector<Image::RGBFTMapEntry> map ;
|
|
image->data->GetColourMap (map) ;
|
|
image->data->SetColourMap (map) ;
|
|
}
|
|
image->data->GetRGBFTIndexedValue(reg, r, g, b, f, t);
|
|
image->data->SetRGBFTIndexedValue(reg, r, g, b, f, Parse_Float());
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
END_EXPECT
|
|
Pigment->Flags |= HAS_FILTER;
|
|
break;
|
|
|
|
default:
|
|
UNGET
|
|
Expectation_Error ("filter or transmit");
|
|
break;
|
|
}
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Pigment->Vals.image=image;
|
|
Parse_End();
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
* Scott Manley Added use of repeat vector
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Bump_Map (TNORMAL *Tnormal)
|
|
{
|
|
ImageData *image;
|
|
|
|
Parse_Begin();
|
|
|
|
image = Parse_Image(IMAGE_FILE);
|
|
image->Use = USE_COLOUR; // was true [trf]
|
|
|
|
EXPECT
|
|
CASE (ONCE_TOKEN)
|
|
image->Once_Flag=true;
|
|
END_CASE
|
|
|
|
CASE (MAP_TYPE_TOKEN)
|
|
image->Map_Type = (int) Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
image->Interpolation_Type = (int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (BUMP_SIZE_TOKEN)
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (USE_COLOUR_TOKEN)
|
|
image->Use = USE_COLOUR; // was true [trf]
|
|
END_CASE
|
|
|
|
CASE (USE_INDEX_TOKEN)
|
|
image->Use = USE_NONE; // was false [trf]
|
|
END_CASE
|
|
|
|
CASE (REPEAT_TOKEN)
|
|
UV_VECT Repeat;
|
|
Parse_UV_Vect (Repeat);
|
|
if ((Repeat[0]<=0.0) || (Repeat[1]<=0.0))
|
|
Error("Zero or Negative Image Repeat Vector.");
|
|
image->width = (DBL)image->iwidth * Repeat[0];
|
|
image->height = (DBL)image->iheight * Repeat[1];
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
Parse_UV_Vect (image->Offset);
|
|
image->Offset[U] *= (DBL)-image->iwidth;
|
|
image->Offset[V] *= (DBL)-image->iheight;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Tnormal->Vals.image = image;
|
|
|
|
Parse_End();
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Nathan Kopp
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Image_Pattern (TPATTERN *TPattern)
|
|
{
|
|
ImageData *image;
|
|
|
|
Parse_Begin();
|
|
|
|
image = Parse_Image(IMAGE_FILE);
|
|
image->Use = USE_COLOUR; // was true [trf]
|
|
|
|
EXPECT
|
|
CASE (ONCE_TOKEN)
|
|
image->Once_Flag=true;
|
|
END_CASE
|
|
|
|
CASE (MAP_TYPE_TOKEN)
|
|
image->Map_Type = (int) Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
image->Interpolation_Type = (int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (USE_COLOUR_TOKEN)
|
|
image->Use = USE_COLOUR;
|
|
END_CASE
|
|
|
|
CASE (USE_INDEX_TOKEN)
|
|
image->Use = USE_INDEX;
|
|
END_CASE
|
|
|
|
CASE (USE_ALPHA_TOKEN)
|
|
image->Use = USE_ALPHA;
|
|
END_CASE
|
|
|
|
CASE (REPEAT_TOKEN)
|
|
UV_VECT Repeat;
|
|
Parse_UV_Vect (Repeat);
|
|
if ((Repeat[0]<=0.0) || (Repeat[1]<=0.0))
|
|
Error("Zero or Negative Image Repeat Vector.");
|
|
image->width = (DBL)image->iwidth * Repeat[0];
|
|
image->height = (DBL)image->iheight * Repeat[1];
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
Parse_UV_Vect (image->Offset);
|
|
image->Offset[U] *= (DBL)-image->iwidth;
|
|
image->Offset[V] *= (DBL)-image->iheight;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
TPattern->Vals.image = image;
|
|
|
|
Parse_End();
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Pigment (PIGMENT **Pigment_Ptr)
|
|
{
|
|
EXPECT /* Look for [pigment_id] */
|
|
CASE (PIGMENT_ID_TOKEN)
|
|
Destroy_Pigment(*Pigment_Ptr);
|
|
*Pigment_Ptr = Copy_Pigment ((PIGMENT *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT /* End pigment_id */
|
|
|
|
Parse_Pattern((TPATTERN *)(*Pigment_Ptr),PIGMENT_TYPE);
|
|
|
|
if (Not_In_Default && ((*Pigment_Ptr)->Type == NO_PATTERN))
|
|
{
|
|
Warning(155, "Pigment type unspecified or not 1st item.");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Pattern (TPATTERN *New, int TPat_Type)
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
TURB *Local_Turb;
|
|
unsigned short Old_Type=New->Type;
|
|
ImageData *Old_Image = NULL;
|
|
DENSITY_FILE *Old_Density_File = NULL;
|
|
int i;
|
|
SNGL Tot_Len;
|
|
TraceThreadData *Thread = GetParserDataPtr();
|
|
UCS2String ign;
|
|
|
|
if (Old_Type==BITMAP_PATTERN)
|
|
{
|
|
Old_Image=New->Vals.image;
|
|
}
|
|
|
|
if (Old_Type==DENSITY_FILE_PATTERN)
|
|
{
|
|
Old_Density_File=New->Vals.Density_File;
|
|
}
|
|
|
|
EXPECT
|
|
CASE (AGATE_TOKEN)
|
|
New->Type = AGATE_PATTERN;
|
|
Check_Turb(&(New->Warps));
|
|
New->Vals.Agate_Turb_Scale = 1.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BOZO_TOKEN)
|
|
New->Type = BOZO_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (FUNCTION_TOKEN)
|
|
New->Type = FUNCTION_PATTERN;
|
|
New->Vals.Function.vm = sceneData->functionVM;
|
|
New->Vals.Function.Data = sceneData->functionPatternCount;
|
|
sceneData->functionPatternCount++;
|
|
GetParserDataPtr()->functionPatternContext.resize(sceneData->functionPatternCount);
|
|
New->Vals.Function.Fn = Parse_Function();
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(PIGMENT_PATTERN_TOKEN)
|
|
Parse_Begin();
|
|
New->Type = PIGMENT_PATTERN;
|
|
New->Vals.Pigment = Create_Pigment();
|
|
Parse_Pigment(&(New->Vals.Pigment));
|
|
Post_Pigment(New->Vals.Pigment);
|
|
Parse_End();
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (GRANITE_TOKEN)
|
|
New->Type = GRANITE_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (LEOPARD_TOKEN)
|
|
New->Type = LEOPARD_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MARBLE_TOKEN)
|
|
New->Type = MARBLE_PATTERN;
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MANDEL_TOKEN)
|
|
New->Type = MANDEL_PATTERN;
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
New->Vals.Fractal.Exponent = 2;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (JULIA_TOKEN)
|
|
New->Type = JULIA_PATTERN;
|
|
Parse_UV_Vect(New->Vals.Fractal.Coord);
|
|
Parse_Comma();
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
New->Vals.Fractal.Exponent = 2;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MAGNET_TOKEN)
|
|
New->Type = NO_PATTERN;
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
New->Vals.Fractal.Exponent = 0;
|
|
i = (int)Parse_Float();
|
|
EXPECT
|
|
CASE (MANDEL_TOKEN)
|
|
switch(i)
|
|
{
|
|
case 1:
|
|
New->Type = MAGNET1M_PATTERN;
|
|
break;
|
|
case 2:
|
|
New->Type = MAGNET2M_PATTERN;
|
|
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;
|
|
break;
|
|
case 2:
|
|
New->Type = MAGNET2J_PATTERN;
|
|
break;
|
|
default:
|
|
Error("Invalid magnet-julia pattern type found. Valid types are 1 and 2.");
|
|
break;
|
|
}
|
|
Parse_UV_Vect(New->Vals.Fractal.Coord);
|
|
Parse_Comma();
|
|
EXIT
|
|
END_CASE
|
|
OTHERWISE
|
|
Error("Invalid magnet pattern found. Valid types are 'mandel' and 'julia'.");
|
|
END_CASE
|
|
END_EXPECT
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (ONION_TOKEN)
|
|
New->Type = ONION_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPIRAL1_TOKEN)
|
|
New->Type = SPIRAL1_PATTERN;
|
|
New->Vals.Arms = (short)Parse_Float ();
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPIRAL2_TOKEN)
|
|
New->Type = SPIRAL2_PATTERN;
|
|
New->Vals.Arms = (short)Parse_Float ();
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPOTTED_TOKEN)
|
|
New->Type = SPOTTED_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WOOD_TOKEN)
|
|
New->Type = WOOD_PATTERN;
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (GRADIENT_TOKEN)
|
|
New->Type = GRADIENT_PATTERN;
|
|
Parse_Vector (New->Vals.Gradient);
|
|
VNormalizeEq(New->Vals.Gradient);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (RADIAL_TOKEN)
|
|
New->Type = RADIAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CRACKLE_TOKEN)
|
|
New->Type = CRACKLE_PATTERN;
|
|
New->Vals.Crackle.IsSolid = 0;
|
|
New->Vals.Crackle.Form[X] = -1;
|
|
New->Vals.Crackle.Form[Y] = 1;
|
|
New->Vals.Crackle.Form[Z] = 0;
|
|
New->Vals.Crackle.Metric = 2;
|
|
New->Vals.Crackle.Offset = 0;
|
|
New->Vals.Crackle.Dim = 3;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE_COLOUR
|
|
if ((TPat_Type != PIGMENT_TYPE) && (TPat_Type != DENSITY_TYPE))
|
|
{
|
|
Only_In("color","pigment or density");
|
|
}
|
|
New->Type = PLAIN_PATTERN;
|
|
Parse_Colour (((PIGMENT *)New)->colour);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (UV_MAPPING_TOKEN)
|
|
New->Type = UV_MAP_PATTERN;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Item_Into_Blend_List(TPat_Type);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CHECKER_TOKEN)
|
|
New->Type = CHECKER_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(2,&Check_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (OBJECT_TOKEN)
|
|
{
|
|
Parse_Begin();
|
|
vector<ObjectPtr> tempObjects;
|
|
Parse_Bound_Clip(tempObjects, false);
|
|
if(tempObjects.size() != 1)
|
|
Error ("object or object identifier expected.");
|
|
New->Vals.Object = tempObjects[0];
|
|
New->Type = OBJECT_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(2, &Check_Default_Map, TPat_Type);
|
|
Parse_End();
|
|
EXIT
|
|
}
|
|
END_CASE
|
|
|
|
CASE (CELLS_TOKEN)
|
|
New->Type = CELLS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BRICK_TOKEN)
|
|
if (New->Type!=BRICK_PATTERN)
|
|
{
|
|
Make_Vector(New->Vals.Brick.Size,8.0,3.0,4.5);
|
|
New->Vals.Brick.Mortar=0.5-EPSILON*2.0;
|
|
New->Type = BRICK_PATTERN;
|
|
}
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(2,&Brick_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (HEXAGON_TOKEN)
|
|
New->Type = HEXAGON_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(3,&Hex_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SQUARE_TOKEN)
|
|
New->Type = SQUARE_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(4,&Square_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (TRIANGULAR_TOKEN)
|
|
New->Type = TRIANGULAR_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(6,&Triangular_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
// JN2007: Cubic pattern
|
|
CASE (CUBIC_TOKEN)
|
|
New->Type = CUBIC_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_List(6,&Cubic_Default_Map,TPat_Type);
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
((TNORMAL *)New)->Delta = 0.02;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (IMAGE_MAP_TOKEN)
|
|
if (TPat_Type != PIGMENT_TYPE)
|
|
{
|
|
Only_In("image_map","pigment");
|
|
}
|
|
|
|
if (Old_Type==BITMAP_PATTERN)
|
|
{
|
|
Destroy_Image(Old_Image);
|
|
}
|
|
|
|
New->Type = BITMAP_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Parse_Image_Map ((PIGMENT *)New);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BUMP_MAP_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Only_In("bump_map","normal");
|
|
}
|
|
|
|
if (Old_Type==BITMAP_PATTERN)
|
|
{
|
|
Destroy_Image(Old_Image);
|
|
}
|
|
|
|
New->Type = BITMAP_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Parse_Bump_Map ((TNORMAL *)New);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WAVES_TOKEN)
|
|
New->Type = WAVES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (RIPPLES_TOKEN)
|
|
New->Type = RIPPLES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WRINKLES_TOKEN)
|
|
New->Type = WRINKLES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BUMPS_TOKEN)
|
|
New->Type = BUMPS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (DENTS_TOKEN)
|
|
New->Type = DENTS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (QUILTED_TOKEN)
|
|
New->Type = QUILTED_PATTERN;
|
|
New->Vals.Quilted.Control0 = 1.0;
|
|
New->Vals.Quilted.Control1 = 1.0;
|
|
New->Frequency = 0.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (FACETS_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Only_In("facets","normal");
|
|
}
|
|
New->Type = FACETS_PATTERN;
|
|
New->Vals.Facets.Size = 0.1;
|
|
New->Vals.Facets.UseCoords = 0;
|
|
New->Vals.Facets.Metric = 2;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (AVERAGE_TOKEN)
|
|
New->Type = AVERAGE_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (IMAGE_PATTERN_TOKEN)
|
|
if ((Old_Type==BITMAP_PATTERN) || (Old_Type==IMAGE_PATTERN))
|
|
{
|
|
Destroy_Image(Old_Image);
|
|
}
|
|
|
|
New->Type = IMAGE_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Parse_Image_Pattern (New);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (PLANAR_TOKEN)
|
|
New->Type = PLANAR_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BOXED_TOKEN)
|
|
New->Type = BOXED_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPHERICAL_TOKEN)
|
|
New->Type = SPHERICAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CYLINDRICAL_TOKEN)
|
|
New->Type = CYLINDRICAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (DENSITY_FILE_TOKEN)
|
|
if (Old_Type==DENSITY_FILE_PATTERN)
|
|
{
|
|
Destroy_Density_File(Old_Density_File);
|
|
}
|
|
New->Type = DENSITY_FILE_PATTERN;
|
|
New->Vals.Density_File = Create_Density_File();
|
|
GET(DF3_TOKEN);
|
|
New->Vals.Density_File->Data->Name = Parse_C_String(true);
|
|
{
|
|
IStream *dfile = Locate_File(this, sceneData, ASCIItoUCS2String(New->Vals.Density_File->Data->Name).c_str(), POV_File_Data_DF3, ign, true);
|
|
if(dfile == NULL)
|
|
Error("Cannot read media density file.");
|
|
Read_Density_File(dfile, New->Vals.Density_File);
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SLOPE_TOKEN)
|
|
New->Type = SLOPE_PATTERN;
|
|
New->Vals.Slope.Altit_Vector[X] = 0.0;
|
|
New->Vals.Slope.Altit_Vector[Y] = 0.0;
|
|
New->Vals.Slope.Altit_Vector[Z] = 0.0;
|
|
New->Vals.Slope.Slope_Mod[U] = 0.0;
|
|
New->Vals.Slope.Altit_Mod[U] = 0.0;
|
|
New->Vals.Slope.Slope_Mod[V] = 0.0;
|
|
New->Vals.Slope.Altit_Mod[V] = 0.0;
|
|
New->Vals.Slope.Point_At = false;
|
|
|
|
EXPECT
|
|
/* simple syntax */
|
|
CASE_EXPRESS
|
|
Parse_Vector (New->Vals.Slope.Slope_Vector);
|
|
EXIT
|
|
END_CASE
|
|
|
|
/* new syntax */
|
|
CASE(LEFT_CURLY_TOKEN)
|
|
UNGET
|
|
Parse_Begin();
|
|
|
|
EXPECT_ONE
|
|
CASE(POINT_AT_TOKEN)
|
|
New->Vals.Slope.Point_At = true;
|
|
EXIT
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
/* parse the vector */
|
|
Parse_Vector (New->Vals.Slope.Slope_Vector);
|
|
|
|
/* allow low slope, high slope */
|
|
Parse_Comma();
|
|
New->Vals.Slope.Slope_Mod[0] = Allow_Float(0.0);
|
|
Parse_Comma();
|
|
New->Vals.Slope.Slope_Mod[1] = Allow_Float(0.0);
|
|
|
|
|
|
if (New->Vals.Slope.Slope_Mod[V] != 0.0 &&
|
|
New->Vals.Slope.Slope_Mod[V] == New->Vals.Slope.Slope_Mod[U])
|
|
{
|
|
New->Vals.Slope.Slope_Mod[U] = 0.0;
|
|
New->Vals.Slope.Slope_Mod[V] = 0.0;
|
|
Warning (0, "Zero slope range, ignoring.");
|
|
}
|
|
else
|
|
{
|
|
New->Vals.Slope.Slope_Mod[V] -= New->Vals.Slope.Slope_Mod[U];
|
|
}
|
|
|
|
EXPECT
|
|
CASE(ALTITUDE_TOKEN)
|
|
if (New->Vals.Slope.Point_At)
|
|
{
|
|
Error("Keyword 'altitude' cannot be used with 'point_at' in slope pattern.");
|
|
}
|
|
else
|
|
{
|
|
Experimental_Flag |= EF_SLOPEM; // this feature is experimental
|
|
Parse_Vector (New->Vals.Slope.Altit_Vector);
|
|
|
|
/* allow low alt, high alt */
|
|
Parse_Comma();
|
|
New->Vals.Slope.Altit_Mod[0] = Allow_Float(0.0);
|
|
Parse_Comma();
|
|
New->Vals.Slope.Altit_Mod[1] = Allow_Float(0.0);
|
|
|
|
if (New->Vals.Slope.Altit_Mod[V] != 0.0 &&
|
|
New->Vals.Slope.Altit_Mod[V] == New->Vals.Slope.Altit_Mod[U])
|
|
{
|
|
New->Vals.Slope.Altit_Mod[U] = 0.0;
|
|
New->Vals.Slope.Altit_Mod[V] = 0.0;
|
|
Warning (0, "Zero gradient range, ignoring.");
|
|
}
|
|
else
|
|
{
|
|
New->Vals.Slope.Altit_Mod[V] -= New->Vals.Slope.Altit_Mod[U];
|
|
}
|
|
}
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
|
|
Parse_End();
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if (New->Vals.Slope.Point_At)
|
|
{
|
|
New->Vals.Slope.Slope_Len = 1.0;
|
|
New->Vals.Slope.Altit_Len = 0.0;
|
|
}
|
|
else
|
|
{
|
|
VLength(New->Vals.Slope.Slope_Len, New->Vals.Slope.Slope_Vector);
|
|
VLength(New->Vals.Slope.Altit_Len, New->Vals.Slope.Altit_Vector);
|
|
|
|
if (New->Vals.Slope.Slope_Len != 0.0) VNormalizeEq(New->Vals.Slope.Slope_Vector);
|
|
if (New->Vals.Slope.Altit_Len != 0.0) VNormalizeEq(New->Vals.Slope.Altit_Vector);
|
|
|
|
Tot_Len = New->Vals.Slope.Slope_Len + New->Vals.Slope.Altit_Len;
|
|
|
|
if (Tot_Len != 0.0)
|
|
{
|
|
New->Vals.Slope.Slope_Len /= Tot_Len;
|
|
New->Vals.Slope.Altit_Len = 1.0 - New->Vals.Slope.Slope_Len;
|
|
}
|
|
else
|
|
{
|
|
Error ("Zero length for both slope and gradient.");
|
|
}
|
|
}
|
|
|
|
/* pre-process some stuff (look for shortcuts) for speed rendering speed */
|
|
New->Vals.Slope.Slope_Base = New->Vals.Slope.Altit_Base = 0; /* mark unused */
|
|
if (!New->Vals.Slope.Point_At)
|
|
{
|
|
for (i=X; i<=Z; i++)
|
|
{
|
|
if (New->Vals.Slope.Slope_Vector[i] == 1.0) { New->Vals.Slope.Slope_Base = i+1; break; }
|
|
else if (New->Vals.Slope.Slope_Vector[i] == -1.0) { New->Vals.Slope.Slope_Base = -(i+1); break; }
|
|
}
|
|
for (i=X; i<=Z; i++)
|
|
{
|
|
if (New->Vals.Slope.Altit_Vector[i] == 1.0) { New->Vals.Slope.Altit_Base = i+1; break; }
|
|
else if (New->Vals.Slope.Altit_Vector[i] == -1.0) { New->Vals.Slope.Altit_Base = -(i+1); break; }
|
|
}
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (AOI_TOKEN)
|
|
New->Type = AOI_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (PAVEMENT_TOKEN)
|
|
New->Type = PAVEMENT_PATTERN;
|
|
New->Vals.Pavement.Side = 3;
|
|
New->Vals.Pavement.Tile = 1;
|
|
New->Vals.Pavement.Number = 1;
|
|
New->Vals.Pavement.Exterior = 0;
|
|
New->Vals.Pavement.Interior = 0;
|
|
New->Vals.Pavement.Form = 0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (TILING_TOKEN)
|
|
New->Type = TILING_PATTERN;
|
|
New->Vals.Tiling.Pattern = (unsigned char)Parse_Float();
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT /* Concludes pattern_body */
|
|
|
|
if ((Old_Type==BITMAP_PATTERN) && (New->Type!=BITMAP_PATTERN))
|
|
{
|
|
Destroy_Image(Old_Image);
|
|
}
|
|
|
|
if ((Old_Type==DENSITY_FILE_PATTERN) && (New->Type!=DENSITY_FILE_PATTERN))
|
|
{
|
|
Destroy_Density_File(Old_Density_File);
|
|
}
|
|
|
|
if (TPat_Type == NORMAL_TYPE)
|
|
{
|
|
Parse_Comma();
|
|
((TNORMAL *)New)->Amount = Allow_Float (((TNORMAL *)New)->Amount );
|
|
}
|
|
|
|
EXPECT /* Look for pattern_modifier */
|
|
CASE (ACCURACY_TOKEN)
|
|
if(TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Error("accuracy can only be used with normal patterns.");
|
|
}
|
|
((TNORMAL *)New)->Delta = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (SOLID_TOKEN)
|
|
if (New->Type != CRACKLE_PATTERN )
|
|
{
|
|
Only_In("solid", "crackle");
|
|
}
|
|
New->Vals.Crackle.IsSolid = 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)
|
|
{
|
|
New->Vals.Pavement.Exterior = (unsigned char)Parse_Float();
|
|
}
|
|
else
|
|
{
|
|
New->Vals.Fractal.exterior_type = (int)Parse_Float();
|
|
if((New->Vals.Fractal.exterior_type < 0) || (New->Vals.Fractal.exterior_type > 8))
|
|
Error("Invalid fractal pattern exterior type. Valid types are 0 to 8.");
|
|
Parse_Comma();
|
|
New->Vals.Fractal.efactor = 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)))
|
|
{
|
|
Only_In("exterior", "mandel, julia, magnet or pavement");
|
|
}
|
|
else if (New->Type == PAVEMENT_PATTERN)
|
|
{
|
|
New->Vals.Pavement.Interior = (unsigned char)Parse_Float();
|
|
}
|
|
else
|
|
{
|
|
New->Vals.Fractal.interior_type = (int)Parse_Float();
|
|
if((New->Vals.Fractal.interior_type < 0) || (New->Vals.Fractal.interior_type > 6))
|
|
Error("Invalid fractal pattern interior type. Valid types are 0 to 6.");
|
|
Parse_Comma();
|
|
New->Vals.Fractal.ifactor = 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)))
|
|
{
|
|
Only_In("exponent", "mandel or julia");
|
|
}
|
|
|
|
if((New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) || (New->Type == JULIA4_PATTERN))
|
|
{
|
|
New->Vals.Fractal.Exponent = i = (int)Parse_Float();
|
|
switch(i)
|
|
{
|
|
case 2:
|
|
New->Type = JULIA_PATTERN;
|
|
break;
|
|
case 3:
|
|
New->Type = JULIA3_PATTERN;
|
|
break;
|
|
case 4:
|
|
New->Type = JULIA4_PATTERN;
|
|
break;
|
|
default:
|
|
if((i > 4) && (i <= 33))
|
|
{
|
|
New->Type = JULIAX_PATTERN;
|
|
}
|
|
else
|
|
{
|
|
New->Type = JULIA_PATTERN;
|
|
Warning(0, "Invalid julia pattern exponent found. Supported exponents are 2 to 33.\n"
|
|
"Using default exponent 2.");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) || (New->Type == MANDEL4_PATTERN))
|
|
{
|
|
New->Vals.Fractal.Exponent = i = (int)Parse_Float();
|
|
switch(i)
|
|
{
|
|
case 2:
|
|
New->Type = MANDEL_PATTERN;
|
|
break;
|
|
case 3:
|
|
New->Type = MANDEL3_PATTERN;
|
|
break;
|
|
case 4:
|
|
New->Type = MANDEL4_PATTERN;
|
|
break;
|
|
default:
|
|
if((i > 4) && (i <= 33))
|
|
{
|
|
New->Type = MANDELX_PATTERN;
|
|
}
|
|
else
|
|
{
|
|
New->Type = MANDEL_PATTERN;
|
|
Warning(0, "Invalid mandel pattern exponent found. Supported exponents are 2 to 33.\n"
|
|
"Using default exponent 2.");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
END_CASE
|
|
|
|
CASE (COORDS_TOKEN)
|
|
if (New->Type != FACETS_PATTERN )
|
|
{
|
|
Only_In("coords", "facets");
|
|
}
|
|
New->Vals.Facets.UseCoords = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (SIZE_TOKEN)
|
|
if (New->Type == FACETS_PATTERN )
|
|
{
|
|
New->Vals.Facets.Size = Parse_Float();
|
|
}
|
|
else
|
|
{
|
|
Only_In("size", "facets");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (METRIC_TOKEN)
|
|
if (New->Type == FACETS_PATTERN )
|
|
{
|
|
Parse_Vector(Local_Vector);
|
|
New->Vals.Facets.Metric = Local_Vector[X];
|
|
}
|
|
else
|
|
{
|
|
if ( New->Type == CRACKLE_PATTERN )
|
|
{
|
|
// Vector for backwards compatibility
|
|
// the only component used was always X.
|
|
Parse_Vector(Local_Vector);
|
|
New->Vals.Crackle.Metric = Local_Vector[X];
|
|
}
|
|
else
|
|
{
|
|
Only_In("metric", "facets or crackle");
|
|
}
|
|
}
|
|
END_CASE
|
|
|
|
CASE (FORM_TOKEN)
|
|
if ((New->Type != CRACKLE_PATTERN) && (New->Type != PAVEMENT_PATTERN))
|
|
{
|
|
Only_In("form", "crackle or pavement");
|
|
}
|
|
else if (New->Type == CRACKLE_PATTERN)
|
|
{
|
|
Parse_Vector( New->Vals.Crackle.Form );
|
|
}
|
|
else
|
|
{
|
|
New->Vals.Pavement.Form = ((unsigned char)Parse_Float());
|
|
}
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
if (New->Type != CRACKLE_PATTERN )
|
|
{
|
|
Only_In("offset", "crackle");
|
|
}
|
|
New->Vals.Crackle.Offset = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (TURBULENCE_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Parse_Vector(Local_Turb->Turbulence);
|
|
END_CASE
|
|
|
|
CASE (COLOUR_MAP_TOKEN)
|
|
if ((TPat_Type != PIGMENT_TYPE) && (TPat_Type != DENSITY_TYPE))
|
|
{
|
|
Only_In("color_map","pigment");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == AVERAGE_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
{
|
|
Error("Cannot use color_map with this pattern type.");
|
|
}
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Colour_Map ();
|
|
END_CASE
|
|
|
|
CASE (PIGMENT_MAP_TOKEN)
|
|
if (TPat_Type != PIGMENT_TYPE)
|
|
{
|
|
Only_In("pigment_map","pigment");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("pigment_map","this pigment type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (PIGMENT_TYPE,New->Type);
|
|
END_CASE
|
|
|
|
CASE (DENSITY_MAP_TOKEN)
|
|
if (TPat_Type != DENSITY_TYPE)
|
|
{
|
|
Only_In("density_map","density");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("density_map","this density type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (DENSITY_TYPE,New->Type);
|
|
END_CASE
|
|
|
|
CASE (SLOPE_MAP_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Only_In("slope_map","normal");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == AVERAGE_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("slope_map","this normal type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (SLOPE_TYPE,New->Type);
|
|
END_CASE
|
|
|
|
CASE (NORMAL_MAP_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Only_In("normal_map","normal");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == FACETS_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("normal_map","this normal type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (NORMAL_TYPE,New->Type);
|
|
END_CASE
|
|
|
|
CASE (TEXTURE_MAP_TOKEN)
|
|
if (TPat_Type != TEXTURE_TYPE)
|
|
{
|
|
Only_In("texture_map","texture");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == SQUARE_PATTERN ||
|
|
New->Type == TRIANGULAR_PATTERN ||
|
|
New->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == OBJECT_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("texture_map","this pattern type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (TEXTURE_TYPE,New->Type);
|
|
END_CASE
|
|
|
|
CASE (QUICK_COLOUR_TOKEN)
|
|
if (TPat_Type != PIGMENT_TYPE)
|
|
{
|
|
Only_In("quick_color","pigment");
|
|
}
|
|
Parse_Colour (((PIGMENT *)New)->Quick_Colour);
|
|
END_CASE
|
|
|
|
CASE (CONTROL0_TOKEN)
|
|
if (New->Type == QUILTED_PATTERN)
|
|
{
|
|
New->Vals.Quilted.Control0 = Parse_Float ();
|
|
}
|
|
else
|
|
{
|
|
Not_With ("control0","this pattern");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (CONTROL1_TOKEN)
|
|
if (New->Type == QUILTED_PATTERN)
|
|
{
|
|
New->Vals.Quilted.Control1 = Parse_Float ();
|
|
}
|
|
else
|
|
{
|
|
Not_With ("control1","this pattern");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (OCTAVES_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Octaves = (int)Parse_Float();
|
|
if(Local_Turb->Octaves < 1)
|
|
Local_Turb->Octaves = 1;
|
|
if(Local_Turb->Octaves > 10) /* Avoid DOMAIN errors */
|
|
Local_Turb->Octaves = 10;
|
|
END_CASE
|
|
|
|
CASE (OMEGA_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Omega = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (LAMBDA_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Lambda = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (FREQUENCY_TOKEN)
|
|
New->Frequency = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (RAMP_WAVE_TOKEN)
|
|
New->Wave_Type = RAMP_WAVE;
|
|
END_CASE
|
|
|
|
CASE (TRIANGLE_WAVE_TOKEN)
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
END_CASE
|
|
|
|
CASE (SINE_WAVE_TOKEN)
|
|
New->Wave_Type = SINE_WAVE;
|
|
END_CASE
|
|
|
|
CASE (SCALLOP_WAVE_TOKEN)
|
|
New->Wave_Type = SCALLOP_WAVE;
|
|
END_CASE
|
|
|
|
CASE (CUBIC_WAVE_TOKEN)
|
|
New->Wave_Type = CUBIC_WAVE;
|
|
END_CASE
|
|
|
|
CASE (POLY_WAVE_TOKEN)
|
|
New->Wave_Type = POLY_WAVE;
|
|
New->Exponent = Allow_Float(New->Exponent);
|
|
END_CASE
|
|
|
|
CASE (PHASE_TOKEN)
|
|
New->Phase = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (BUMP_SIZE_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
Only_In ("bump_size","normal");
|
|
((TNORMAL *)New)->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (NOISE_GENERATOR_TOKEN)
|
|
{
|
|
int noise_generator;
|
|
noise_generator = (int) Parse_Float();
|
|
if (noise_generator < 0 || noise_generator > 3)
|
|
Error ("Value for noise_generator must be 0, 1, 2, or 3.");
|
|
New->Flags |= noise_generator * NOISE_FLAG_1;
|
|
}
|
|
END_CASE
|
|
|
|
CASE (AGATE_TURB_TOKEN)
|
|
if (New->Type != AGATE_PATTERN)
|
|
Not_With ("agate_turb","non-agate");
|
|
New->Vals.Agate_Turb_Scale = Parse_Float();
|
|
Check_Turb(&(New->Warps)); /* agate needs Octaves, Lambda etc. */
|
|
END_CASE
|
|
|
|
CASE (BRICK_SIZE_TOKEN)
|
|
if (New->Type != BRICK_PATTERN)
|
|
Not_With ("brick_size","non-brick");
|
|
Parse_Vector(New->Vals.Brick.Size);
|
|
END_CASE
|
|
|
|
CASE (MORTAR_TOKEN)
|
|
if (New->Type != BRICK_PATTERN)
|
|
Not_With ("mortar","non-brick");
|
|
New->Vals.Brick.Mortar = Parse_Float()-EPSILON*2.0;
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
if (New->Type != DENSITY_FILE_PATTERN)
|
|
Not_With ("interpolate","non-density_file");
|
|
New->Vals.Density_File->Interpolation = (int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (NUMBER_OF_SIDES_TOKEN)
|
|
if (New->Type != PAVEMENT_PATTERN)
|
|
Only_In("number_of_sides","pavement");
|
|
New->Vals.Pavement.Side=(unsigned char)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (NUMBER_OF_TILES_TOKEN)
|
|
if (New->Type != PAVEMENT_PATTERN)
|
|
Only_In("number_of_tiles","pavement");
|
|
New->Vals.Pavement.Tile=(unsigned char)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (PATTERN_TOKEN)
|
|
if (New->Type != PAVEMENT_PATTERN)
|
|
Only_In("pattern","pavement");
|
|
New->Vals.Pavement.Number=(unsigned char)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (WARP_TOKEN)
|
|
Parse_Warp(&(New->Warps));
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Translate_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Rotate_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Scale_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Tpattern (New, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Tpattern (New, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
CASE (NO_BUMP_SCALE_TOKEN)
|
|
Set_Flag(New,DONT_SCALE_BUMPS_FLAG);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if ((New->Type==AVERAGE_PATTERN) && (New->Blend_Map==NULL))
|
|
{
|
|
Error("Average must have map.");
|
|
}
|
|
|
|
if ((TPat_Type==TEXTURE_TYPE) && (New->Type!=PLAIN_PATTERN) &&
|
|
(New->Blend_Map==NULL))
|
|
{
|
|
Error("Patterned texture must have texture_map.");
|
|
}
|
|
|
|
if ((New->Type==PAVEMENT_PATTERN))
|
|
{
|
|
const int valid6[]={1,1,3,7,22};
|
|
const int valid4[]={1,1,2,5,12,35};
|
|
const int valid3[]={1,1,1,3,4,12};
|
|
New->Vals.Pavement.Interior %= 3;
|
|
New->Vals.Pavement.Exterior %= 3;
|
|
switch(New->Vals.Pavement.Side)
|
|
{
|
|
case 4:
|
|
if ((!(New->Vals.Pavement.Tile)) || (New->Vals.Pavement.Tile>6))
|
|
{
|
|
Error("number_of_tiles of pavement must be between 1 and 6.");
|
|
}
|
|
else if ((!(New->Vals.Pavement.Number)) || (New->Vals.Pavement.Number > valid4[New->Vals.Pavement.Tile - 1]))
|
|
{
|
|
Error("pattern value for pavement is out of range. max per tile:(1,1,2,5,12,35)");
|
|
}
|
|
New->Vals.Pavement.Form %=4;
|
|
break;
|
|
|
|
case 6:
|
|
if ((!(New->Vals.Pavement.Tile)) || (New->Vals.Pavement.Tile > 5))
|
|
{
|
|
Error("number_of_tiles of pavement must be between 1 and 5.");
|
|
}
|
|
else if ((!(New->Vals.Pavement.Number)) || (New->Vals.Pavement.Number > valid6[New->Vals.Pavement.Tile - 1]))
|
|
{
|
|
Error("pattern value for pavement is out of range. max per tile:(1,1,3,7,22)");
|
|
}
|
|
New->Vals.Pavement.Form %= 3;
|
|
break;
|
|
|
|
case 3:
|
|
if ((!(New->Vals.Pavement.Tile)) || (New->Vals.Pavement.Tile > 6))
|
|
{
|
|
Error("number_of_tiles of pavement must be between 1 and 6.");
|
|
}
|
|
else if ((!(New->Vals.Pavement.Number)) || (New->Vals.Pavement.Number > valid3[New->Vals.Pavement.Tile - 1]))
|
|
{
|
|
Error("pattern value for pavement is out of range. max per tile:(1,1,1,3,4,12)");
|
|
}
|
|
New->Vals.Pavement.Form %= 3;
|
|
break;
|
|
|
|
default:
|
|
Error("number_of_sides of pavement must be 3, 4 or 6.");
|
|
}
|
|
|
|
}
|
|
|
|
if ((New->Type==TILING_PATTERN) && ((New->Vals.Tiling.Pattern < 1) || (New->Vals.Tiling.Pattern > 27)))
|
|
{
|
|
Error("Tiling number must be between 1 and 27.");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Tnormal (TNORMAL **Tnormal_Ptr)
|
|
{
|
|
EXPECT /* Look for [tnormal_id] */
|
|
CASE (TNORMAL_ID_TOKEN)
|
|
Destroy_Tnormal(*Tnormal_Ptr);
|
|
*Tnormal_Ptr = Copy_Tnormal ((TNORMAL *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT /* End [tnormal_id] */
|
|
|
|
if (*Tnormal_Ptr == NULL)
|
|
{
|
|
if ((Default_Texture->Tnormal) != NULL)
|
|
{
|
|
*Tnormal_Ptr = Copy_Tnormal ((Default_Texture->Tnormal));
|
|
}
|
|
else
|
|
{
|
|
*Tnormal_Ptr = Create_Tnormal ();
|
|
}
|
|
}
|
|
Parse_Pattern((TPATTERN *)*Tnormal_Ptr,NORMAL_TYPE);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Finish (FINISH **Finish_Ptr)
|
|
{
|
|
Colour Temp_Colour;
|
|
FINISH *New;
|
|
VECTOR Local_Vector;
|
|
bool diffuseAdjust = false;
|
|
bool phongAdjust = false;
|
|
bool specularAdjust = false;
|
|
|
|
Parse_Begin ();
|
|
|
|
EXPECT /* Look for zero or one finish_id */
|
|
CASE (FINISH_ID_TOKEN)
|
|
Destroy_Finish(*Finish_Ptr);
|
|
*Finish_Ptr = Copy_Finish ((FINISH *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT /* End finish_id */
|
|
|
|
New = *Finish_Ptr;
|
|
|
|
EXPECT /* Look for zero or more finish_body */
|
|
CASE (CONSERVE_ENERGY_TOKEN)
|
|
New->Conserve_Energy = true;
|
|
END_CASE
|
|
|
|
CASE (AMBIENT_TOKEN)
|
|
Parse_Colour(New->Ambient);
|
|
END_CASE
|
|
|
|
CASE (EMISSION_TOKEN)
|
|
Parse_Colour(New->Emission);
|
|
END_CASE
|
|
|
|
CASE (BRILLIANCE_TOKEN)
|
|
New->Brilliance = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (DIFFUSE_TOKEN)
|
|
EXPECT
|
|
CASE (ALBEDO_TOKEN)
|
|
diffuseAdjust = true;
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
New->Diffuse = Parse_Float ();
|
|
Parse_Comma();
|
|
New->DiffuseBack = Allow_Float(0.0);
|
|
if (New->DiffuseBack != 0.0)
|
|
Experimental_Flag |= EF_BACKILL;
|
|
END_CASE
|
|
|
|
CASE (REFLECTION_TOKEN)
|
|
{
|
|
bool found_second_color = false;
|
|
EXPECT
|
|
/* old syntax */
|
|
CASE_EXPRESS
|
|
Parse_Colour(New->Reflection_Max);
|
|
New->Reflection_Min = New->Reflection_Max;
|
|
New->Reflection_Falloff = 1;
|
|
New->Reflection_Type = 0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
/* new syntax */
|
|
CASE(LEFT_CURLY_TOKEN)
|
|
UNGET
|
|
Parse_Begin();
|
|
|
|
/* parse the first colour */
|
|
Parse_Colour(New->Reflection_Min);
|
|
Parse_Comma();
|
|
|
|
/* look for a second color */
|
|
EXPECT
|
|
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
|
|
|
|
/* look for a other options */
|
|
EXPECT
|
|
CASE(FRESNEL_TOKEN)
|
|
New->Reflection_Type = (int) Allow_Float(1.0);
|
|
if (New->Reflection_Type < 0 || New->Reflection_Type > 1)
|
|
{
|
|
Error("fresnel must be true or false");
|
|
}
|
|
|
|
/* for fresnel reflectivity, if the user didn't specify a min & max,
|
|
then we will set the min to zero - otherwise, this setting would
|
|
have no effect */
|
|
if(!found_second_color && New->Reflection_Type > 0)
|
|
{
|
|
New->Reflection_Min.clear();
|
|
}
|
|
END_CASE
|
|
|
|
CASE (FALLOFF_TOKEN)
|
|
New->Reflection_Falloff = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (EXPONENT_TOKEN)
|
|
New->Reflect_Exp = 1.0 / Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (METALLIC_TOKEN)
|
|
New->Reflect_Metallic = Allow_Float(1.0);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
|
|
END_EXPECT
|
|
}
|
|
END_CASE
|
|
|
|
CASE (REFLECTION_EXPONENT_TOKEN)
|
|
New->Reflect_Exp = 1.0 / Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (PHONG_TOKEN)
|
|
EXPECT
|
|
CASE (ALBEDO_TOKEN)
|
|
phongAdjust = true;
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
New->Phong = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (PHONG_SIZE_TOKEN)
|
|
New->Phong_Size = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (SPECULAR_TOKEN)
|
|
EXPECT
|
|
CASE (ALBEDO_TOKEN)
|
|
specularAdjust = true;
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
New->Specular = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (ROUGHNESS_TOKEN)
|
|
New->Roughness = Parse_Float ();
|
|
if (New->Roughness != 0.0)
|
|
New->Roughness = 1.0/New->Roughness; /* CEY 12/92 */
|
|
else
|
|
Warning(0, "Zero roughness used.");
|
|
END_CASE
|
|
|
|
CASE (METALLIC_TOKEN)
|
|
New->Metallic = 1.0;
|
|
EXPECT
|
|
CASE_FLOAT
|
|
New->Metallic = Parse_Float();
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
END_CASE
|
|
|
|
CASE (CRAND_TOKEN)
|
|
New->Crand = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (IRID_TOKEN) /* DMF */
|
|
Parse_Begin();
|
|
New->Irid = Parse_Float();
|
|
|
|
EXPECT
|
|
CASE (THICKNESS_TOKEN) /* DMF */
|
|
New->Irid_Film_Thickness = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (TURBULENCE_TOKEN) /* DMF */
|
|
Parse_Vector(Local_Vector);
|
|
New->Irid_Turb = Local_Vector[X];
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
CASE (IOR_TOKEN)
|
|
New->Temp_IOR = Parse_Float();
|
|
Warn_Compat(0, "Index of refraction value should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
CASE (CAUSTICS_TOKEN)
|
|
New->Temp_Caustics = Parse_Float();
|
|
Warn_Compat(0, "Caustics value should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
CASE (REFRACTION_TOKEN)
|
|
New->Temp_Refract = Parse_Float();
|
|
Warn_Compat(0, "Refraction value unnecessary to turn on refraction.\nTo attenuate, the fade_power and fade_distance keywords should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
CASE (SUBSURFACE_TOKEN)
|
|
Experimental_Flag |= EF_SSLT;
|
|
New->UseSubsurface = true;
|
|
Parse_Begin();
|
|
EXPECT
|
|
CASE (ANISOTROPY_TOKEN)
|
|
Parse_Colour(New->SubsurfaceAnisotropy);
|
|
END_CASE
|
|
CASE (TRANSLUCENCY_TOKEN)
|
|
Parse_Colour(New->SubsurfaceTranslucency);
|
|
END_CASE
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
|
|
END_EXPECT /* End of finish_body */
|
|
|
|
#if 0
|
|
EXPECT /* Look for finish_mods */
|
|
|
|
/* CASE none implemented - if you implement one remember to remove the #if 0 and the #endif
|
|
around this block of code
|
|
END_CASE */
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT /* End of finish_mods */
|
|
#endif
|
|
|
|
// If requested by the user via the "albedo" keyword,
|
|
// adjust diffuse, phong and/or specular intensity parameters
|
|
// so that a user-specified value of 1.0 corresponds to a
|
|
// backscattering of 100% of the incoming light
|
|
New->RawDiffuse = New->Diffuse;
|
|
New->RawDiffuseBack = New->DiffuseBack;
|
|
if (diffuseAdjust)
|
|
{
|
|
New->Diffuse *= (New->Brilliance + 1.0) / 2.0;
|
|
New->DiffuseBack *= (New->Brilliance + 1.0) / 2.0;
|
|
}
|
|
if (phongAdjust)
|
|
New->Phong *= (New->Phong_Size + 1.0) / 2.0;
|
|
if (specularAdjust)
|
|
New->Specular *= (New->Roughness + 2.0) / (4.0 * ( 2.0 - pow( 2.0, -New->Roughness / 2.0 ) ) );
|
|
|
|
Parse_End ();
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
TEXTURE *Parser::Parse_Texture ()
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
TEXTURE *Texture;
|
|
int Modified_Pnf;
|
|
|
|
if (sceneData->languageVersion < 300)
|
|
{
|
|
return(Parse_Vers1_Texture());
|
|
}
|
|
|
|
Modified_Pnf = false;
|
|
|
|
EXPECT /* First allow a texture identifier */
|
|
CASE (TEXTURE_ID_TOKEN)
|
|
Texture = Copy_Textures((TEXTURE *) Token.Data);
|
|
Modified_Pnf = true;
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
Texture = Copy_Textures (Default_Texture);
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
/* If the texture identifer or the default texture was a PLAIN_PATTERN
|
|
then allow its pigment, normal or finish to be overridden by
|
|
pigment identifier, normal identifier and finish identifiers.
|
|
This is a consession to backwards compatibility so that
|
|
"texture{PIGMENT_IDENTIFIER}" etc. is legal even though it should
|
|
be "texture{pigment{PIGMENT_IDENTIFIER}}"
|
|
*/
|
|
|
|
/* Look for [pnf_texture] */
|
|
if (Texture->Type == PLAIN_PATTERN)
|
|
{
|
|
EXPECT /* Look for [pnf_ids] */
|
|
CASE (PIGMENT_ID_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Destroy_Pigment(Texture->Pigment);
|
|
Texture->Pigment = Copy_Pigment ((PIGMENT *) Token.Data);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (TNORMAL_ID_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
Destroy_Tnormal(Texture->Tnormal);
|
|
Texture->Tnormal = Copy_Tnormal ((TNORMAL *) Token.Data);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (FINISH_ID_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Destroy_Finish(Texture->Finish);
|
|
Texture->Finish = Copy_Finish ((FINISH *) Token.Data);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
/* If the texture identifer or the default texture was a PLAIN_PATTERN
|
|
then allow its pigment, normal or finish to be overridden by
|
|
pigment, normal or finish statement. Also allow transformations.
|
|
*/
|
|
|
|
EXPECT /* Modify previous pnf */
|
|
CASE (PIGMENT_TOKEN)
|
|
Parse_Begin ();
|
|
Parse_Pigment ( &(Texture->Pigment) );
|
|
Parse_End ();
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (TNORMAL_TOKEN)
|
|
Parse_Begin ();
|
|
Parse_Tnormal ( &(Texture->Tnormal) );
|
|
Parse_End ();
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (FINISH_TOKEN)
|
|
Parse_Finish ( &(Texture->Finish) );
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Translation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Textures (Texture, Parse_Transform(&Local_Trans));
|
|
Modified_Pnf = true;
|
|
END_CASE
|
|
|
|
CASE (NO_BUMP_SCALE_TOKEN)
|
|
Set_Flag(Texture,DONT_SCALE_BUMPS_FLAG);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
}
|
|
else
|
|
{
|
|
/* Here it is not a PLAIN_PATTERN texture and since default textures
|
|
must be plain then this was a texture identifier that was a special
|
|
texture. Allow transforms. The "if(!Modified_Pnf)..." below
|
|
will always fail if we came here. So we return after the
|
|
transforms. */
|
|
Parse_Texture_Transform(Texture);
|
|
}
|
|
|
|
/* If we've modified the default texture with a p,n, or f then this
|
|
has to stay a PLAIN_PATTERN pnf texture. We won't allow
|
|
a texture_map or pattern. Therefore quit now.
|
|
*/
|
|
|
|
if (!Modified_Pnf)
|
|
{
|
|
/* At this point we've either got a texture statement that had
|
|
no p, n or f. Nor any texture identifier. Its probably
|
|
a patterned texture_map texture. */
|
|
|
|
EXPECT
|
|
CASE (TILES_TOKEN)
|
|
Destroy_Textures (Texture);
|
|
Texture = Parse_Tiles();
|
|
if (Texture->Blend_Map->Blend_Map_Entries[1].Vals.Texture == 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
|
|
UNGET;
|
|
Destroy_Pigment(Texture->Pigment);
|
|
Destroy_Tnormal(Texture->Tnormal);
|
|
Destroy_Finish(Texture->Finish);
|
|
Texture->Pigment = NULL;
|
|
Texture->Tnormal = NULL;
|
|
Texture->Finish = NULL;
|
|
Parse_Pattern((TPATTERN *)Texture,TEXTURE_TYPE);
|
|
/* if following is true, parsed "texture{}" so restore
|
|
default texture.
|
|
*/
|
|
if (Texture->Type <= PLAIN_PATTERN)
|
|
{
|
|
Destroy_Textures(Texture);
|
|
Texture = Copy_Textures (Default_Texture);
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
}
|
|
|
|
return (Texture);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
TEXTURE *Parser::Parse_Tiles()
|
|
{
|
|
TEXTURE *Texture, *Local_Texture;
|
|
BLEND_MAP_ENTRY *Entry;
|
|
|
|
Parse_Begin ();
|
|
|
|
Texture = Create_Texture ();
|
|
Destroy_Pigment(Texture->Pigment);
|
|
Destroy_Tnormal(Texture->Tnormal);
|
|
Destroy_Finish(Texture->Finish);
|
|
Texture->Pigment = NULL;
|
|
Texture->Tnormal = NULL;
|
|
Texture->Finish = NULL;
|
|
Texture->Type = CHECKER_PATTERN;
|
|
|
|
Texture->Blend_Map = Create_Blend_Map();
|
|
Texture->Blend_Map->Number_Of_Entries = 2;
|
|
Texture->Blend_Map->Blend_Map_Entries = Entry = Create_BMap_Entries (2);
|
|
Texture->Blend_Map->Type = TEXTURE_TYPE;
|
|
Entry[0].Vals.Texture=NULL;
|
|
Entry[0].value=0.0;
|
|
Entry[0].Same=false;
|
|
Entry[1].Vals.Texture=NULL;
|
|
Entry[1].value=1.0;
|
|
Entry[1].Same=false;
|
|
|
|
/* Note first tile is 1, 2nd tile is 0 to keep compatible with old tiles */
|
|
|
|
EXPECT
|
|
CASE (TEXTURE_TOKEN)
|
|
Parse_Begin ();
|
|
Local_Texture = Parse_Texture ();
|
|
Link_Textures(&(Entry[1].Vals.Texture),Local_Texture);
|
|
Parse_End ();
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
GET (TILE2_TOKEN);
|
|
|
|
EXPECT
|
|
CASE (TEXTURE_TOKEN)
|
|
Parse_Begin ();
|
|
Local_Texture = Parse_Texture ();
|
|
Link_Textures(&(Entry[0].Vals.Texture),Local_Texture);
|
|
Parse_End ();
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End ();
|
|
|
|
return (Texture);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
TEXTURE *Parser::Parse_Material_Map()
|
|
{
|
|
TEXTURE *Texture, *Local_Texture;
|
|
Parse_Begin ();
|
|
|
|
Texture = Create_Texture ();
|
|
Destroy_Pigment(Texture->Pigment);
|
|
Destroy_Tnormal(Texture->Tnormal);
|
|
Destroy_Finish(Texture->Finish);
|
|
Texture->Pigment = NULL;
|
|
Texture->Tnormal = NULL;
|
|
Texture->Finish = NULL;
|
|
Texture->Type = BITMAP_PATTERN;
|
|
|
|
Texture->Vals.image = Parse_Image(MATERIAL_FILE);
|
|
Texture->Vals.image->Use = USE_NONE; // was false [trf]
|
|
|
|
EXPECT
|
|
CASE (ONCE_TOKEN)
|
|
Texture->Vals.image->Once_Flag=true;
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
Texture->Vals.image->Interpolation_Type=(int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (MAP_TYPE_TOKEN)
|
|
Texture->Vals.image->Map_Type = (int) Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (REPEAT_TOKEN)
|
|
UV_VECT Repeat;
|
|
Parse_UV_Vect (Repeat);
|
|
if ((Repeat[0]<=0.0) || (Repeat[1]<=0.0))
|
|
Error("Zero or Negative Image Repeat Vector.");
|
|
Texture->Vals.image->width = (DBL)Texture->Vals.image->iwidth * Repeat[0];
|
|
Texture->Vals.image->height = (DBL)Texture->Vals.image->iheight * Repeat[1];
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
Parse_UV_Vect (Texture->Vals.image->Offset);
|
|
Texture->Vals.image->Offset[U] *= (DBL)-Texture->Vals.image->iwidth;
|
|
Texture->Vals.image->Offset[V] *= (DBL)-Texture->Vals.image->iheight;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
GET (TEXTURE_TOKEN) /* First material */
|
|
Parse_Begin();
|
|
Texture->Materials = Local_Texture = Parse_Texture ();
|
|
Parse_End();
|
|
Texture->Num_Of_Mats++;
|
|
|
|
EXPECT /* Subsequent materials */
|
|
CASE (TEXTURE_TOKEN)
|
|
Parse_Begin();
|
|
Local_Texture->Next_Material = Parse_Texture ();
|
|
Parse_End();
|
|
Local_Texture = Local_Texture->Next_Material;
|
|
Texture->Num_Of_Mats++;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End ();
|
|
|
|
return(Texture);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
TEXTURE *Parser::Parse_Vers1_Texture ()
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
TURB *Local_Turb;
|
|
TEXTURE *Texture;
|
|
PIGMENT *Pigment;
|
|
TNORMAL *Tnormal;
|
|
FINISH *Finish;
|
|
|
|
EXPECT /* Look for texture_body */
|
|
CASE (TILES_TOKEN)
|
|
Texture = Parse_Tiles();
|
|
if (Texture->Blend_Map->Blend_Map_Entries[1].Vals.Texture == 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((TEXTURE *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
Texture = Copy_Textures (Default_Texture);
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
/* Look for [pnf_texture] */
|
|
if (Texture->Type == PLAIN_PATTERN)
|
|
{
|
|
EXPECT /* Look for [pnf_ids] */
|
|
CASE (PIGMENT_ID_TOKEN)
|
|
Destroy_Pigment(Texture->Pigment);
|
|
Texture->Pigment = Copy_Pigment ((PIGMENT *) Token.Data);
|
|
END_CASE
|
|
|
|
CASE (TNORMAL_ID_TOKEN)
|
|
Destroy_Tnormal(Texture->Tnormal);
|
|
Texture->Tnormal = Copy_Tnormal ((TNORMAL *) Token.Data);
|
|
END_CASE
|
|
|
|
CASE (FINISH_ID_TOKEN)
|
|
Destroy_Finish(Texture->Finish);
|
|
Texture->Finish = Copy_Finish ((FINISH *) Token.Data);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Pigment = Texture->Pigment;
|
|
Tnormal = Texture->Tnormal;
|
|
Finish = Texture->Finish;
|
|
|
|
EXPECT
|
|
CASE (PIGMENT_TOKEN)
|
|
Parse_Begin ();
|
|
Parse_Pigment ( &(Texture->Pigment) );
|
|
Parse_End ();
|
|
END_CASE
|
|
|
|
CASE (TNORMAL_TOKEN)
|
|
Parse_Begin ();
|
|
Parse_Tnormal ( &(Texture->Tnormal) );
|
|
Parse_End ();
|
|
END_CASE
|
|
|
|
CASE (FINISH_TOKEN)
|
|
Parse_Finish ( &(Texture->Finish) );
|
|
END_CASE
|
|
|
|
/***********************************************************************
|
|
PIGMENT STUFF OUTSIDE PIGMENT{}
|
|
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->Vals.Agate_Turb_Scale = 1.0;
|
|
Check_Turb(&(Pigment->Warps)); /* agate needs Octaves, Lambda etc. */
|
|
END_CASE
|
|
|
|
CASE (BOZO_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = BOZO_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (GRANITE_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = GRANITE_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (LEOPARD_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = LEOPARD_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (MARBLE_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = MARBLE_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (MANDEL_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = MANDEL_PATTERN;
|
|
Pigment->Vals.Iterations = (int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (ONION_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = ONION_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (SPOTTED_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = SPOTTED_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (WOOD_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = WOOD_PATTERN;
|
|
END_CASE
|
|
|
|
CASE (GRADIENT_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = GRADIENT_PATTERN;
|
|
Parse_Vector (Pigment->Vals.Gradient);
|
|
VNormalizeEq(Pigment->Vals.Gradient);
|
|
END_CASE
|
|
|
|
CASE_COLOUR
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = PLAIN_PATTERN;
|
|
Parse_Colour (Pigment->colour);
|
|
END_CASE
|
|
|
|
CASE (CHECKER_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = CHECKER_PATTERN;
|
|
Pigment->Frequency = 0.0;
|
|
Destroy_Blend_Map(Pigment->Blend_Map);
|
|
Pigment->Blend_Map = Parse_Blend_List(2,&Check_Default_Map,COLOUR_TYPE);
|
|
END_CASE
|
|
|
|
CASE (HEXAGON_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = HEXAGON_PATTERN;
|
|
Pigment->Frequency = 0.0;
|
|
Destroy_Blend_Map(Pigment->Blend_Map);
|
|
Pigment->Blend_Map = Parse_Blend_List(3,&Hex_Default_Map,COLOUR_TYPE);
|
|
END_CASE
|
|
|
|
CASE (SQUARE_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = SQUARE_PATTERN;
|
|
Pigment->Frequency = 0.0;
|
|
Destroy_Blend_Map(Pigment->Blend_Map);
|
|
Pigment->Blend_Map = Parse_Blend_List(4,&Square_Default_Map,COLOUR_TYPE);
|
|
END_CASE
|
|
|
|
CASE (TRIANGULAR_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = TRIANGULAR_PATTERN;
|
|
Pigment->Frequency = 0.0;
|
|
Destroy_Blend_Map(Pigment->Blend_Map);
|
|
Pigment->Blend_Map = Parse_Blend_List(6,&Triangular_Default_Map,COLOUR_TYPE);
|
|
END_CASE
|
|
|
|
CASE (IMAGE_MAP_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Pigment->Type = BITMAP_PATTERN;
|
|
Pigment->Frequency = 0.0;
|
|
Parse_Image_Map (Pigment);
|
|
END_CASE
|
|
|
|
CASE (TURBULENCE_TOKEN)
|
|
Local_Turb=Check_Turb(&(Pigment->Warps));
|
|
Parse_Vector(Local_Turb->Turbulence);
|
|
END_CASE
|
|
|
|
CASE (COLOUR_MAP_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
if (Pigment->Type == CHECKER_PATTERN ||
|
|
Pigment->Type == HEXAGON_PATTERN ||
|
|
Pigment->Type == SQUARE_PATTERN ||
|
|
Pigment->Type == TRIANGULAR_PATTERN ||
|
|
Pigment->Type == CUBIC_PATTERN || // JN2007: Cubic pattern
|
|
Pigment->Type == PLAIN_PATTERN ||
|
|
Pigment->Type == BITMAP_PATTERN)
|
|
Warning(150, "Cannot use color map with this pigment type.");
|
|
Destroy_Blend_Map(Pigment->Blend_Map);
|
|
Pigment->Blend_Map = Parse_Colour_Map ();
|
|
END_CASE
|
|
|
|
CASE (QUICK_COLOUR_TOKEN)
|
|
Warn_State(Token.Token_Id, PIGMENT_TOKEN);
|
|
Parse_Colour (Pigment->Quick_Colour);
|
|
END_CASE
|
|
|
|
CASE (OCTAVES_TOKEN)
|
|
Local_Turb=Check_Turb(&(Pigment->Warps));
|
|
Local_Turb->Octaves = (int)Parse_Float();
|
|
if(Local_Turb->Octaves < 1)
|
|
Local_Turb->Octaves = 1;
|
|
if(Local_Turb->Octaves > 10) /* Avoid DOMAIN errors */
|
|
Local_Turb->Octaves = 10;
|
|
END_CASE
|
|
|
|
CASE (OMEGA_TOKEN)
|
|
Local_Turb=Check_Turb(&(Pigment->Warps));
|
|
Local_Turb->Omega = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (LAMBDA_TOKEN)
|
|
Local_Turb=Check_Turb(&(Pigment->Warps));
|
|
Local_Turb->Lambda = Parse_Float();
|
|
END_CASE
|
|
|
|
/***********************************************************************
|
|
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);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = BUMPS_PATTERN;
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (DENTS_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = DENTS_PATTERN;
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (RIPPLES_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = RIPPLES_PATTERN;
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (WAVES_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = WAVES_PATTERN;
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (WRINKLES_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = WRINKLES_PATTERN;
|
|
Tnormal->Amount = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (BUMP_MAP_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
Tnormal->Type = BITMAP_PATTERN;
|
|
Tnormal->Frequency = 0.0;
|
|
Parse_Bump_Map (Tnormal);
|
|
END_CASE
|
|
|
|
CASE (FREQUENCY_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
if (!(Tnormal->Type == RIPPLES_PATTERN || Tnormal->Type == WAVES_PATTERN))
|
|
if (sceneData->languageVersion >= 150)
|
|
Warning(150, "Cannot use frequency with this normal.");
|
|
Tnormal->Frequency = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (PHASE_TOKEN)
|
|
Warn_State(Token.Token_Id, TNORMAL_TOKEN);
|
|
ADD_TNORMAL
|
|
if (!(Tnormal->Type == RIPPLES_PATTERN || Tnormal->Type == WAVES_PATTERN))
|
|
if (sceneData->languageVersion >= 150)
|
|
Warning(150, "Cannot use phase with this normal.");
|
|
Tnormal->Phase = Parse_Float();
|
|
END_CASE
|
|
|
|
|
|
/***********************************************************************
|
|
FINISH STUFF OUTSIDE FINISH{}
|
|
NOTE: Do not add new keywords to this section. Use 1.0 syntax only.
|
|
***********************************************************************/
|
|
CASE (AMBIENT_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Ambient = RGBColour(Parse_Float ());
|
|
END_CASE
|
|
|
|
CASE (BRILLIANCE_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Brilliance = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (DIFFUSE_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Diffuse = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (REFLECTION_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Reflection_Max = RGBColour(Parse_Float ());
|
|
Finish->Reflection_Min = Finish->Reflection_Max;
|
|
Finish->Reflection_Falloff = 1;
|
|
END_CASE
|
|
|
|
CASE (PHONG_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Phong = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (PHONG_SIZE_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Phong_Size = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (SPECULAR_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Specular = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (ROUGHNESS_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Roughness = Parse_Float ();
|
|
if (Finish->Roughness != 0.0)
|
|
Finish->Roughness = 1.0/Finish->Roughness; /* CEY 12/92 */
|
|
else
|
|
Warning(0, "Zero roughness used.");
|
|
END_CASE
|
|
|
|
CASE (METALLIC_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Metallic = 1.0;
|
|
END_CASE
|
|
|
|
CASE (CRAND_TOKEN)
|
|
Warn_State(Token.Token_Id, FINISH_TOKEN);
|
|
Finish->Crand = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE_FLOAT
|
|
Finish->Crand = Parse_Float();
|
|
Warning(150, "Should use crand keyword in finish statement.");
|
|
END_CASE
|
|
|
|
CASE (IOR_TOKEN)
|
|
Warn_State(Token.Token_Id, INTERIOR_TOKEN);
|
|
Finish->Temp_IOR = Parse_Float();
|
|
Warn_Compat(0, "Index of refraction value should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
CASE (REFRACTION_TOKEN)
|
|
Warn_State(Token.Token_Id, INTERIOR_TOKEN);
|
|
Finish->Temp_Refract = Parse_Float();
|
|
Warn_Compat(0, "Refraction value unnecessary to turn on refraction.\nTo attenuate, the fade_power and fade_distance keywords should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Translation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Textures (Texture, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
CASE (TEXTURE_ID_TOKEN)
|
|
Warning(0, "Texture identifier overwriting previous values.");
|
|
Destroy_Textures(Texture);
|
|
Texture = Copy_Textures((TEXTURE *) Token.Data);
|
|
Pigment = Texture->Pigment;
|
|
Tnormal = Texture->Tnormal;
|
|
Finish = Texture->Finish;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
|
|
/***********************************************************************/
|
|
|
|
END_EXPECT
|
|
|
|
if (Not_In_Default && (Texture->Pigment->Type == NO_PATTERN) &&
|
|
!(sceneData->languageVersion < 150))
|
|
Parse_Error(PIGMENT_ID_TOKEN);
|
|
|
|
}
|
|
|
|
Parse_Texture_Transform(Texture);
|
|
|
|
return (Texture);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Texture_Transform (TEXTURE *Texture)
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
|
|
EXPECT
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Translation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Textures (Texture, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Textures (Texture, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
CASE (NO_BUMP_SCALE_TOKEN)
|
|
Set_Flag(Texture,DONT_SCALE_BUMPS_FLAG);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_Media
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Dieter Bayer
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* Dec 1996 : Creation.
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Media(vector<Media>& medialist)
|
|
{
|
|
Media IMediaObj;
|
|
Media *IMedia = &IMediaObj;
|
|
TRANSFORM Local_Trans;
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(MEDIA_ID_TOKEN)
|
|
IMediaObj = *((Media *)Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
/* with version 3.5+, the default media method is now 3 */
|
|
if(sceneData->languageVersion >= 350)
|
|
{
|
|
IMedia->Intervals = 1;
|
|
IMedia->Min_Samples = 10;
|
|
IMedia->Max_Samples = 10;
|
|
IMedia->Sample_Method = 3;
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE (INTERVALS_TOKEN)
|
|
if ((IMedia->Intervals = (int)Parse_Float()) < 1)
|
|
{
|
|
Error("At least one interval is needed in media.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (SAMPLES_TOKEN)
|
|
IMedia->Min_Samples = (int)Parse_Float();
|
|
Parse_Comma();
|
|
IMedia->Max_Samples = (int)Allow_Float(IMedia->Min_Samples);
|
|
if (IMedia->Min_Samples < 1)
|
|
{
|
|
Error("At least one sample per interval is needed in media.");
|
|
}
|
|
if (IMedia->Max_Samples < IMedia->Min_Samples)
|
|
{
|
|
Error("Maximum number of samples per interval smaller than minimum number.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (METHOD_TOKEN)
|
|
IMedia->Sample_Method = (int)Parse_Float();
|
|
if (IMedia->Sample_Method != 1 && IMedia->Sample_Method!= 2 && IMedia->Sample_Method!= 3)
|
|
{
|
|
Error("Sample method choices are 1, 2, or 3.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (JITTER_TOKEN)
|
|
IMedia->Jitter = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (AA_THRESHOLD_TOKEN)
|
|
IMedia->AA_Threshold = Parse_Float();
|
|
if(IMedia->AA_Threshold<=0)
|
|
{
|
|
Error("aa_threshold in media must be greater than zero.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (AA_LEVEL_TOKEN)
|
|
IMedia->AA_Level = (int)Parse_Float();
|
|
if(IMedia->AA_Level<1)
|
|
Error("aa_level in media must be at least one.");
|
|
END_CASE
|
|
|
|
CASE (COLLECT_TOKEN)
|
|
IMedia->ignore_photons = !(Allow_Float(1.0) > 0.0);
|
|
END_CASE
|
|
|
|
CASE (ABSORPTION_TOKEN)
|
|
Parse_Colour(IMedia->Absorption);
|
|
END_CASE
|
|
|
|
CASE (EMISSION_TOKEN)
|
|
Parse_Colour(IMedia->Emission);
|
|
END_CASE
|
|
|
|
CASE (SCATTERING_TOKEN)
|
|
Parse_Begin();
|
|
IMedia->Type = (int)Parse_Float();
|
|
if ((IMedia->Type < 1) || (IMedia->Type > SCATTERING_TYPES))
|
|
{
|
|
Warning(0, "Unknown atmospheric scattering type.");
|
|
}
|
|
Parse_Comma();
|
|
Parse_Colour(IMedia->Scattering);
|
|
|
|
EXPECT
|
|
CASE (ECCENTRICITY_TOKEN)
|
|
if (IMedia->Type != HENYEY_GREENSTEIN_SCATTERING)
|
|
{
|
|
Error("Eccentricity cannot be used with this scattering type.");
|
|
}
|
|
IMedia->Eccentricity = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (EXTINCTION_TOKEN)
|
|
IMedia->sc_ext = Parse_Float();
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
CASE (CONFIDENCE_TOKEN)
|
|
IMedia->Confidence = Parse_Float();
|
|
if ((IMedia->Confidence < 0.0) || (IMedia->Confidence >= 1.0))
|
|
{
|
|
Error("Illegal confidence value in media.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (VARIANCE_TOKEN)
|
|
IMedia->Variance = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (RATIO_TOKEN)
|
|
IMedia->Ratio = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (DENSITY_TOKEN)
|
|
Parse_Begin();
|
|
Parse_Media_Density_Pattern(&(IMedia->Density));
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Translation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Density (IMedia->Density, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Density (IMedia->Density, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Density (IMedia->Density, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Density (IMedia->Density, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Density (IMedia->Density, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
|
|
medialist.push_back(IMediaObj);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_Interior
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Dieter Bayer
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* Jan 1997 : Creation.
|
|
* Sep 1999 : Fade_Colour added - Edward Coffey
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Interior(Interior **Interior_Ptr)
|
|
{
|
|
Interior *interior = NULL;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(INTERIOR_ID_TOKEN)
|
|
Destroy_Interior(*Interior_Ptr);
|
|
if(Token.Data != NULL)
|
|
*Interior_Ptr = new Interior(*(Interior *)Token.Data);
|
|
else
|
|
*Interior_Ptr = new Interior();
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if(*Interior_Ptr == NULL)
|
|
*Interior_Ptr = new Interior();
|
|
|
|
interior = *Interior_Ptr;
|
|
|
|
EXPECT
|
|
CASE (IOR_TOKEN)
|
|
interior->IOR = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (DISPERSION_TOKEN)
|
|
interior->Dispersion = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (DISPERSION_SAMPLES_TOKEN)
|
|
interior->Disp_NElems = (int)Parse_Float();
|
|
if (interior->Disp_NElems < 2)
|
|
Error("Dispersion samples minimum is 2.");
|
|
END_CASE
|
|
|
|
CASE (CAUSTICS_TOKEN)
|
|
interior->Caustics = Parse_Float() * 45.0;
|
|
END_CASE
|
|
|
|
CASE (FADE_COLOUR_TOKEN)
|
|
Parse_Colour(interior->Fade_Colour);
|
|
END_CASE
|
|
|
|
CASE (FADE_DISTANCE_TOKEN)
|
|
interior->Fade_Distance = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (FADE_POWER_TOKEN)
|
|
interior->Fade_Power = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (MEDIA_TOKEN)
|
|
Parse_Media(interior->media);
|
|
END_CASE
|
|
|
|
CASE (REFRACTION_TOKEN)
|
|
interior->Old_Refract = Parse_Float();
|
|
Warn_Compat(0, "Refraction value unnecessary to turn on refraction.\nTo attenuate, the fade_power and fade_distance keywords should be specified in 'interior{...}' statement.");
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_Media_Density_Pattern
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Dieter Bayer
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* Dez 1996 : Creation.
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Media_Density_Pattern(PIGMENT **Density_Ptr)
|
|
{
|
|
PIGMENT *New;
|
|
|
|
EXPECT
|
|
CASE (DENSITY_ID_TOKEN)
|
|
New = Copy_Pigment ((PIGMENT *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
New = Create_Pigment();
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_Pattern((TPATTERN *)New,DENSITY_TYPE);
|
|
|
|
New->Next = (TPATTERN *)(*Density_Ptr);
|
|
*Density_Ptr = New;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
FOG *Parser::Parse_Fog()
|
|
{
|
|
VECTOR Vector;
|
|
MATRIX Matrix;
|
|
TRANSFORM Trans;
|
|
FOG *Fog;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(FOG_ID_TOKEN)
|
|
Fog = Copy_Fog ((FOG *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
Fog = Create_Fog();
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE_COLOUR
|
|
Parse_Colour(Fog->colour);
|
|
END_CASE
|
|
|
|
CASE (DISTANCE_TOKEN)
|
|
Fog->Distance = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE_FLOAT
|
|
Warning(150, "Should use distance keyword.");
|
|
Fog->Distance = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (FOG_TYPE_TOKEN)
|
|
Fog->Type = (int)Parse_Float();
|
|
if ((Fog->Type < ORIG_FOG) || (Fog->Type > FOG_TYPES))
|
|
{
|
|
Warning(0, "Unknown fog type.");
|
|
}
|
|
END_CASE
|
|
|
|
CASE (FOG_ALT_TOKEN)
|
|
Fog->Alt = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (FOG_OFFSET_TOKEN)
|
|
Fog->Offset = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (TURB_DEPTH_TOKEN)
|
|
Fog->Turb_Depth = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (UP_TOKEN)
|
|
Parse_Vector(Fog->Up);
|
|
END_CASE
|
|
|
|
CASE (TURBULENCE_TOKEN)
|
|
if (Fog->Turb == NULL)
|
|
{
|
|
Fog->Turb=(TURB *)Create_Warp(CLASSIC_TURB_WARP);
|
|
}
|
|
Parse_Vector(Fog->Turb->Turbulence);
|
|
END_CASE
|
|
|
|
CASE (OCTAVES_TOKEN)
|
|
if (Fog->Turb == NULL)
|
|
{
|
|
Fog->Turb=(TURB *)Create_Warp(CLASSIC_TURB_WARP);
|
|
}
|
|
Fog->Turb->Octaves = (int)Parse_Float();
|
|
if(Fog->Turb->Octaves < 1)
|
|
Fog->Turb->Octaves = 1;
|
|
if(Fog->Turb->Octaves > 10)
|
|
Fog->Turb->Octaves = 10;
|
|
END_CASE
|
|
|
|
CASE (OMEGA_TOKEN)
|
|
if (Fog->Turb == NULL)
|
|
{
|
|
Fog->Turb=(TURB *)Create_Warp(CLASSIC_TURB_WARP);
|
|
}
|
|
Fog->Turb->Omega = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (LAMBDA_TOKEN)
|
|
if (Fog->Turb == NULL)
|
|
{
|
|
Fog->Turb=(TURB *)Create_Warp(CLASSIC_TURB_WARP);
|
|
}
|
|
Fog->Turb->Lambda = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector(Vector);
|
|
Compute_Rotation_Transform(&Trans, Vector);
|
|
MTransDirection(Fog->Up, Fog->Up, &Trans);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Vector(Vector);
|
|
Compute_Scaling_Transform(&Trans, Vector);
|
|
MTransDirection(Fog->Up, Fog->Up, &Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector(Vector);
|
|
Warning(0, "A fog's up vector can't be translated.");
|
|
/*
|
|
Compute_Translation_Transform(&Trans, Vector);
|
|
MTransDirection(Fog->Up, Fog->Up, &Trans);
|
|
*/
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Matrix);
|
|
Compute_Matrix_Transform(&Trans, Matrix);
|
|
MTransDirection(Fog->Up, Fog->Up, &Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
MTransDirection(Fog->Up, Fog->Up, Parse_Transform(&Trans));
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End ();
|
|
|
|
/* Make sure the up vector is normalized. */
|
|
|
|
VNormalize(Fog->Up, Fog->Up);
|
|
|
|
return(Fog);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_Rainbow
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Dieter Bayer
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* Jul 1994 : Creation.
|
|
*
|
|
* Dec 1994 : Modified to work with multiple rainbows. [DB]
|
|
*
|
|
* Apr 1995 : Added code for rainbow arcs. [DB]
|
|
*
|
|
******************************************************************************/
|
|
|
|
RAINBOW *Parser::Parse_Rainbow()
|
|
{
|
|
int Angle1, Angle2;
|
|
DBL dot;
|
|
RAINBOW *Rainbow;
|
|
|
|
Angle1 = Angle2 = false;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(RAINBOW_ID_TOKEN)
|
|
Rainbow = Copy_Rainbow ((RAINBOW *) Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
Rainbow = Create_Rainbow();
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE (ANGLE_TOKEN)
|
|
Rainbow->Angle = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (DIRECTION_TOKEN)
|
|
Parse_Vector(Rainbow->Antisolar_Vector);
|
|
END_CASE
|
|
|
|
CASE (COLOUR_MAP_TOKEN)
|
|
Rainbow->Pigment = Create_Pigment();
|
|
Rainbow->Pigment->Blend_Map = Parse_Colour_Map();
|
|
Rainbow->Pigment->Type = GRADIENT_PATTERN;
|
|
Make_Vector (Rainbow->Pigment->Vals.Gradient,1.0,0.0,0.0);
|
|
END_CASE
|
|
|
|
CASE (DISTANCE_TOKEN)
|
|
Rainbow->Distance = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (JITTER_TOKEN)
|
|
Rainbow->Jitter = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (WIDTH_TOKEN)
|
|
Rainbow->Width = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (UP_TOKEN)
|
|
Parse_Vector(Rainbow->Up_Vector);
|
|
END_CASE
|
|
|
|
CASE (FALLOFF_ANGLE_TOKEN)
|
|
Angle1 = true;
|
|
Rainbow->Falloff_Angle = Parse_Float();
|
|
if ((Rainbow->Falloff_Angle < 0.0) || (Rainbow->Falloff_Angle > 360.0))
|
|
{
|
|
Error("Illegal falloff angle in rainbow (Use value from 0 to 360 degrees).");
|
|
}
|
|
Rainbow->Falloff_Angle *= M_PI_360;
|
|
END_CASE
|
|
|
|
CASE (ARC_ANGLE_TOKEN)
|
|
Angle2 = true;
|
|
Rainbow->Arc_Angle = Parse_Float();
|
|
if ((Rainbow->Arc_Angle < 0.0) || (Rainbow->Arc_Angle > 360.0))
|
|
{
|
|
Error("Illegal arc angle in rainbow (Use value from 0 to 360 degrees).");
|
|
}
|
|
Rainbow->Arc_Angle *= M_PI_360;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
|
|
/* Setup falloff angle. */
|
|
|
|
if (Angle2 && !Angle1)
|
|
{
|
|
Rainbow->Falloff_Angle = Rainbow->Arc_Angle;
|
|
}
|
|
|
|
/* Test if arc angle is greater or equal to falloff angle. */
|
|
|
|
if (Rainbow->Arc_Angle < Rainbow->Falloff_Angle)
|
|
{
|
|
Error("Arc angle is smaller than falloff angle in rainbow.");
|
|
}
|
|
|
|
/* Get falloff region width.*/
|
|
|
|
Rainbow->Falloff_Width = Rainbow->Arc_Angle - Rainbow->Falloff_Angle;
|
|
|
|
/* Check for illegal vectors. */
|
|
|
|
VDot(dot, Rainbow->Antisolar_Vector, Rainbow->Antisolar_Vector);
|
|
|
|
if (fabs(dot) < EPSILON)
|
|
{
|
|
Error("Rainbow's direction vector is zero.");
|
|
}
|
|
|
|
VDot(dot, Rainbow->Up_Vector, Rainbow->Up_Vector);
|
|
|
|
if (fabs(dot) < EPSILON)
|
|
{
|
|
Error("Rainbow's up vector is zero.");
|
|
}
|
|
|
|
VNormalizeEq(Rainbow->Antisolar_Vector);
|
|
VNormalizeEq(Rainbow->Up_Vector);
|
|
|
|
VDot(dot, Rainbow->Up_Vector, Rainbow->Antisolar_Vector);
|
|
|
|
if (fabs(1.0 - fabs(dot)) < EPSILON)
|
|
{
|
|
Error("Rainbow's up and direction vector are co-linear.");
|
|
}
|
|
|
|
/* Make sure that up and antisolar vector are perpendicular. */
|
|
|
|
VCross(Rainbow->Right_Vector, Rainbow->Up_Vector, Rainbow->Antisolar_Vector);
|
|
|
|
VCross(Rainbow->Up_Vector, Rainbow->Antisolar_Vector, Rainbow->Right_Vector);
|
|
|
|
VNormalizeEq(Rainbow->Up_Vector);
|
|
VNormalizeEq(Rainbow->Right_Vector);
|
|
|
|
/* Adjust rainbow angle and width. */
|
|
|
|
Rainbow->Angle -= 0.5 * Rainbow->Width;
|
|
|
|
Rainbow->Angle *= M_PI_180;
|
|
Rainbow->Width *= M_PI_180;
|
|
|
|
return(Rainbow);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_Skysphere
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Dieter Bayer
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* Jul 1994 : Creation.
|
|
*
|
|
* Dec 1994 : Modified to work with multiple skyspheres. [DB]
|
|
*
|
|
******************************************************************************/
|
|
|
|
SKYSPHERE *Parser::Parse_Skysphere()
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
SKYSPHERE *Skysphere;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(SKYSPHERE_ID_TOKEN)
|
|
Skysphere = Copy_Skysphere((SKYSPHERE *)Token.Data);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
Skysphere = Create_Skysphere();
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE (PIGMENT_TOKEN)
|
|
Skysphere->Count++;
|
|
Skysphere->Pigments = (PIGMENT **)POV_REALLOC(Skysphere->Pigments, Skysphere->Count*sizeof(SKYSPHERE *), "sky-sphere pigment");
|
|
Skysphere->Pigments[Skysphere->Count-1] = Create_Pigment();
|
|
Parse_Begin();
|
|
Parse_Pigment(&(Skysphere->Pigments[Skysphere->Count-1]));
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
CASE (EMISSION_TOKEN)
|
|
Parse_Colour(Skysphere->Emission);
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Translate_Skysphere(Skysphere, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Rotate_Skysphere(Skysphere, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Scale_Skysphere(Skysphere, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Skysphere(Skysphere, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Skysphere(Skysphere, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
|
|
if (Skysphere->Count==0)
|
|
{
|
|
Error("Empty sky_sphere statement.");
|
|
}
|
|
|
|
return(Skysphere);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : Check_BH_Parameters
|
|
*
|
|
* ARGUMENTS : bh - pointer to Black_Hole
|
|
*
|
|
* AUTHOR : CJC [7/95]
|
|
*
|
|
* DESCRIPTION : Applies sanity checks to the parameters of a black hole.
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Check_BH_Parameters (BLACK_HOLE *bh)
|
|
{
|
|
if (bh->Repeat == false) return ;
|
|
|
|
if (bh->Repeat_Vector [X] > 0.0)
|
|
{
|
|
if (bh->Center [X] < bh->Radius)
|
|
bh->Center [X] = bh->Radius ;
|
|
if (bh->Repeat_Vector [X] < bh->Center [X] + bh->Radius + bh->Uncertainty_Vector [X])
|
|
{
|
|
bh->Repeat_Vector [X] = bh->Center [X] + bh->Radius + bh->Uncertainty_Vector [X] ;
|
|
Warning (0, "Black Hole repeat vector X too small ; increased to %g", bh->Repeat_Vector [X]) ;
|
|
}
|
|
if (bh->Repeat_Vector [X] < EPSILON)
|
|
{
|
|
Warning (0,"Black Hole repeat vector X is less than %f ; ignored", (float) EPSILON) ;
|
|
bh->Repeat_Vector [X] = 0.0 ;
|
|
}
|
|
}
|
|
|
|
if (bh->Repeat_Vector [Y] > 0.0)
|
|
{
|
|
if (bh->Center [Y] < bh->Radius)
|
|
bh->Center [Y] = bh->Radius ;
|
|
if (bh->Repeat_Vector [Y] < bh->Center [Y] + bh->Radius + bh->Uncertainty_Vector [Y])
|
|
{
|
|
bh->Repeat_Vector [Y] = bh->Center [Y] + bh->Radius + bh->Uncertainty_Vector [Y] ;
|
|
Warning (0, "Black Hole repeat vector Y too small ; increased to %g", bh->Repeat_Vector [Y]) ;
|
|
}
|
|
if (bh->Repeat_Vector [Y] < EPSILON)
|
|
{
|
|
Warning (0, "Black Hole repeat vector Y is less than %f ; ignored", (float) EPSILON) ;
|
|
bh->Repeat_Vector [Y] = 0.0 ;
|
|
}
|
|
}
|
|
|
|
if (bh->Repeat_Vector [Z] > 0.0)
|
|
{
|
|
if (bh->Center [Z] < bh->Radius)
|
|
bh->Center [Z] = bh->Radius ;
|
|
if (bh->Repeat_Vector [Z] < bh->Center [Z] + bh->Radius + bh->Uncertainty_Vector [Z])
|
|
{
|
|
bh->Repeat_Vector [Z] = bh->Center [Z] + bh->Radius + bh->Uncertainty_Vector [Z] ;
|
|
Warning (0, "Black Hole repeat vector Z too small ; increased to %g", bh->Repeat_Vector [Z]) ;
|
|
}
|
|
if (bh->Repeat_Vector [Z] < EPSILON)
|
|
{
|
|
Warning (0, "Black Hole repeat vector Z is less than %f ; ignored", (float) EPSILON) ;
|
|
bh->Repeat_Vector [Z] = 0.0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Check_Turb
|
|
*
|
|
* INPUT
|
|
*
|
|
* Warps_Ptr : Address where the root warp of a warp list
|
|
* is stored.
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* Warps_Ptr : If *Warps_Ptr is NULL, a classic turb warp
|
|
* is created and a pointer to it is stored
|
|
*
|
|
* RETURNS
|
|
*
|
|
* A pointer to the last warp in the chain which is guarenteed
|
|
* to be a classic turb.
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* CEY [2/95]
|
|
*
|
|
* DESCRIPTION : This routine is called when a classic outside-the-warp
|
|
* turbulence parameter is parsed. One and only one classic turb may exist
|
|
* in a warp chain. If there is one, it must be the last. This routine
|
|
* traverses the warp chain and looks at the last link. If it is not a
|
|
* classic turb then it adds one to the end and returns a pointer to it.
|
|
* If the chain is empty, it creates a single link chain consisting of a
|
|
* classic turb link. Future warp links get added ahead of the chain so
|
|
* that any classic turb link is always last.
|
|
*
|
|
* CHANGES
|
|
*
|
|
******************************************************************************/
|
|
|
|
TURB *Parser::Check_Turb (WARP **Warps_Ptr)
|
|
{
|
|
WARP *Temp=*Warps_Ptr;
|
|
|
|
if (Temp == NULL)
|
|
{
|
|
*Warps_Ptr = Temp = Create_Warp(CLASSIC_TURB_WARP);
|
|
}
|
|
else
|
|
{
|
|
while (Temp->Next_Warp != NULL)
|
|
{
|
|
Temp = Temp->Next_Warp;
|
|
}
|
|
|
|
if (Temp->Warp_Type != CLASSIC_TURB_WARP)
|
|
{
|
|
Temp->Next_Warp = Create_Warp(CLASSIC_TURB_WARP);
|
|
Temp->Next_Warp->Prev_Warp = Temp;
|
|
Temp = Temp->Next_Warp;
|
|
}
|
|
}
|
|
return((TURB *)Temp);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* POV-Ray Team
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
* Talious 10/24/1998: Added SPherical/Cylindrical/Toroidaal warps
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_Warp (WARP **Warp_Ptr)
|
|
{
|
|
WARP *New = NULL;
|
|
TURB *Turb;
|
|
REPEAT *Repeat;
|
|
BLACK_HOLE *Black_Hole;
|
|
VECTOR Local_Vector;
|
|
CYLW *CylW;
|
|
SPHEREW *SphereW;
|
|
TOROIDAL *Toroidal;
|
|
PLANARW *PlanarW;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(TURBULENCE_TOKEN)
|
|
New=Create_Warp(EXTRA_TURB_WARP);
|
|
Turb=(TURB *)New;
|
|
Parse_Vector(Turb->Turbulence);
|
|
EXPECT
|
|
CASE(OCTAVES_TOKEN)
|
|
Turb->Octaves = (int)Parse_Float();
|
|
if(Turb->Octaves < 1)
|
|
Turb->Octaves = 1;
|
|
if(Turb->Octaves > 10) /* Avoid DOMAIN errors */
|
|
Turb->Octaves = 10;
|
|
END_CASE
|
|
|
|
CASE (OMEGA_TOKEN)
|
|
Turb->Omega = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (LAMBDA_TOKEN)
|
|
Turb->Lambda = Parse_Float();
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(REPEAT_TOKEN)
|
|
New=Create_Warp(REPEAT_WARP);
|
|
Repeat=(REPEAT *)New;
|
|
Parse_Vector(Local_Vector);
|
|
Repeat->Axis=-1;
|
|
if (Local_Vector[X]!=0.0)
|
|
{
|
|
Repeat->Axis=X;
|
|
}
|
|
if (Local_Vector[Y]!=0.0)
|
|
{
|
|
if (Repeat->Axis < X)
|
|
{
|
|
Repeat->Axis=Y;
|
|
}
|
|
else
|
|
{
|
|
Error("Can only repeat along 1 axis.");
|
|
}
|
|
}
|
|
if (Local_Vector[Z]!=0.0)
|
|
{
|
|
if (Repeat->Axis < X)
|
|
{
|
|
Repeat->Axis=Z;
|
|
}
|
|
else
|
|
{
|
|
Error("Can only repeat along 1 axis.");
|
|
}
|
|
}
|
|
if (Repeat->Axis < X)
|
|
{
|
|
Error("No axis specified in repeat.");
|
|
}
|
|
Repeat->Width=Local_Vector[Repeat->Axis];
|
|
|
|
EXPECT
|
|
CASE(OFFSET_TOKEN)
|
|
Parse_Vector(Repeat->Offset);
|
|
END_CASE
|
|
|
|
CASE(FLIP_TOKEN)
|
|
Parse_Vector(Repeat->Flip);
|
|
if (Repeat->Flip[X]!=0.0) Repeat->Flip[X]=-1.0; else Repeat->Flip[X]=1.0;
|
|
if (Repeat->Flip[Y]!=0.0) Repeat->Flip[Y]=-1.0; else Repeat->Flip[Y]=1.0;
|
|
if (Repeat->Flip[Z]!=0.0) Repeat->Flip[Z]=-1.0; else Repeat->Flip[Z]=1.0;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(BLACK_HOLE_TOKEN)
|
|
New = Create_Warp(BLACK_HOLE_WARP) ;
|
|
Black_Hole = (BLACK_HOLE *) New ;
|
|
Parse_Vector (Local_Vector) ;
|
|
Assign_Vector (Black_Hole->Center, Local_Vector) ;
|
|
Parse_Comma () ;
|
|
Black_Hole->Radius = Parse_Float () ;
|
|
Black_Hole->Radius_Squared = Black_Hole->Radius * Black_Hole->Radius ;
|
|
Black_Hole->Inverse_Radius = 1.0 / Black_Hole->Radius;
|
|
Black_Hole->Strength = 1.0 ;
|
|
Black_Hole->Power = 2.0 ;
|
|
Black_Hole->Inverted = false ;
|
|
Black_Hole->Type = 0 ;
|
|
|
|
EXPECT
|
|
CASE(STRENGTH_TOKEN)
|
|
Black_Hole->Strength = Parse_Float () ;
|
|
END_CASE
|
|
|
|
CASE(FALLOFF_TOKEN)
|
|
Black_Hole->Power = Parse_Float () ;
|
|
END_CASE
|
|
|
|
CASE(INVERSE_TOKEN)
|
|
Black_Hole->Inverted = true ;
|
|
END_CASE
|
|
|
|
CASE(TYPE_TOKEN)
|
|
Black_Hole->Type = (int) Parse_Float () ;
|
|
END_CASE
|
|
|
|
CASE(REPEAT_TOKEN)
|
|
Parse_Vector (Black_Hole->Repeat_Vector) ;
|
|
Black_Hole->Repeat = true ;
|
|
Check_BH_Parameters (Black_Hole) ;
|
|
END_CASE
|
|
|
|
CASE(TURBULENCE_TOKEN)
|
|
Parse_Vector (Black_Hole->Uncertainty_Vector) ;
|
|
Black_Hole->Uncertain = true ;
|
|
Check_BH_Parameters (Black_Hole) ;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(CYLINDRICAL_TOKEN)
|
|
New = Create_Warp(CYLINDRICAL_WARP);
|
|
CylW = (CYLW *) New ;
|
|
EXPECT
|
|
CASE(ORIENTATION_TOKEN)
|
|
Parse_Vector (Local_Vector) ;
|
|
VNormalizeEq(Local_Vector);
|
|
Assign_Vector (CylW->Orientation_Vector, Local_Vector) ;
|
|
END_CASE
|
|
|
|
CASE(DIST_EXP_TOKEN)
|
|
CylW->DistExp = Parse_Float () ;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(SPHERICAL_TOKEN)
|
|
New = Create_Warp(SPHERICAL_WARP);
|
|
SphereW = (SPHEREW *) New ;
|
|
EXPECT
|
|
CASE(ORIENTATION_TOKEN)
|
|
Parse_Vector (Local_Vector) ;
|
|
VNormalizeEq(Local_Vector);
|
|
Assign_Vector (SphereW->Orientation_Vector, Local_Vector) ;
|
|
END_CASE
|
|
|
|
CASE(DIST_EXP_TOKEN)
|
|
SphereW->DistExp = Parse_Float () ;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(PLANAR_TOKEN)
|
|
New = Create_Warp(PLANAR_WARP);
|
|
PlanarW = (PLANARW *) New ;
|
|
if(Allow_Vector(Local_Vector))
|
|
{
|
|
VNormalizeEq(Local_Vector);
|
|
Assign_Vector(PlanarW->Orientation_Vector,Local_Vector);
|
|
Parse_Comma();
|
|
PlanarW->OffSet=Parse_Float();
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(TOROIDAL_TOKEN)
|
|
New = Create_Warp(TOROIDAL_WARP);
|
|
Toroidal = (TOROIDAL *) New ;
|
|
EXPECT
|
|
CASE(ORIENTATION_TOKEN)
|
|
Parse_Vector (Local_Vector) ;
|
|
VNormalizeEq(Local_Vector);
|
|
Assign_Vector (Toroidal->Orientation_Vector, Local_Vector) ;
|
|
END_CASE
|
|
|
|
CASE(DIST_EXP_TOKEN)
|
|
Toroidal->DistExp = Parse_Float () ;
|
|
END_CASE
|
|
|
|
CASE(MAJOR_RADIUS_TOKEN)
|
|
Toroidal->MajorRadius = Parse_Float () ;
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
EXIT
|
|
END_CASE
|
|
|
|
// JN2007: Cubic warp
|
|
CASE(CUBIC_TOKEN)
|
|
New = Create_Warp(CUBIC_WARP);
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
Expectation_Error ("warp type");
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
if (New==NULL)
|
|
{
|
|
Error("Empty warp statement.");
|
|
}
|
|
|
|
New->Next_Warp = *Warp_Ptr;
|
|
if(*Warp_Ptr != NULL)
|
|
(*Warp_Ptr)->Prev_Warp = New;
|
|
*Warp_Ptr = New;
|
|
|
|
Parse_End();
|
|
}
|
|
|
|
|
|
void Parser::Parse_Material(MATERIAL *Material)
|
|
{
|
|
MATERIAL *Temp;
|
|
TEXTURE *Texture;
|
|
TEXTURE * Int_Texture;
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
|
|
Parse_Begin();
|
|
|
|
EXPECT
|
|
CASE(MATERIAL_ID_TOKEN)
|
|
Temp = (MATERIAL *)Token.Data;
|
|
Texture = Copy_Textures(Temp->Texture);
|
|
Int_Texture = Copy_Textures(Temp->Interior_Texture);
|
|
Link_Textures(&(Material->Texture),Texture);
|
|
Link_Textures(&(Material->Interior_Texture),Int_Texture);
|
|
Destroy_Interior(Material->interior);
|
|
if (Temp->interior != NULL)
|
|
Material->interior = new Interior(*(Temp->interior));
|
|
else
|
|
Material->interior = NULL;
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE (TEXTURE_TOKEN)
|
|
Parse_Begin ();
|
|
Texture = Parse_Texture ();
|
|
Parse_End ();
|
|
Link_Textures(&(Material->Texture),Texture);
|
|
END_CASE
|
|
|
|
CASE (INTERIOR_TEXTURE_TOKEN)
|
|
Parse_Begin ();
|
|
Int_Texture = Parse_Texture ();
|
|
Parse_End ();
|
|
Link_Textures(&(Material->Interior_Texture), Int_Texture);
|
|
END_CASE
|
|
|
|
CASE (INTERIOR_TOKEN)
|
|
Parse_Interior((Interior **)(&(Material->interior)));
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Translation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Material->Texture, &Local_Trans);
|
|
if(Material->interior!= NULL)
|
|
Material->interior->Transform(&Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Material->Texture, &Local_Trans);
|
|
if(Material->interior!= NULL)
|
|
Material->interior->Transform(&Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
|
|
Transform_Textures (Material->Texture, &Local_Trans);
|
|
if(Material->interior!= NULL)
|
|
Material->interior->Transform(&Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Textures (Material->Texture, &Local_Trans);
|
|
if(Material->interior!= NULL)
|
|
Material->interior->Transform(&Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Parse_Transform(&Local_Trans);
|
|
Transform_Textures (Material->Texture, &Local_Trans);
|
|
if(Material->interior!= NULL)
|
|
Material->interior->Transform(&Local_Trans);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
Parse_End();
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parse_PatternFunction
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parser::Parse_PatternFunction(TPATTERN *New)
|
|
{
|
|
VECTOR Local_Vector;
|
|
MATRIX Local_Matrix;
|
|
TRANSFORM Local_Trans;
|
|
TURB *Local_Turb;
|
|
unsigned short Old_Type=New->Type;
|
|
ImageData *Old_Image = NULL;
|
|
DENSITY_FILE *Old_Density_File = NULL;
|
|
int i;
|
|
SceneThreadData *Thread = GetParserDataPtr();
|
|
UCS2String ign;
|
|
|
|
EXPECT
|
|
CASE (AGATE_TOKEN)
|
|
New->Type = AGATE_PATTERN;
|
|
Check_Turb(&(New->Warps));
|
|
New->Vals.Agate_Turb_Scale = 1.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BOZO_TOKEN)
|
|
New->Type = BOZO_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE(PIGMENT_PATTERN_TOKEN)
|
|
Parse_Begin();
|
|
New->Type = PIGMENT_PATTERN;
|
|
New->Vals.Pigment = Create_Pigment();
|
|
Parse_Pigment(&(New->Vals.Pigment));
|
|
Post_Pigment(New->Vals.Pigment);
|
|
Parse_End();
|
|
END_CASE
|
|
|
|
CASE (FUNCTION_TOKEN)
|
|
New->Type = FUNCTION_PATTERN;
|
|
New->Vals.Function.vm = sceneData->functionVM;
|
|
New->Vals.Function.Data = sceneData->functionPatternCount;
|
|
sceneData->functionPatternCount++;
|
|
GetParserDataPtr()->functionPatternContext.resize(sceneData->functionPatternCount);
|
|
New->Vals.Function.Fn = Parse_Function();
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (GRANITE_TOKEN)
|
|
New->Type = GRANITE_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (LEOPARD_TOKEN)
|
|
New->Type = LEOPARD_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MARBLE_TOKEN)
|
|
New->Type = MARBLE_PATTERN;
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MANDEL_TOKEN)
|
|
New->Type = MANDEL_PATTERN;
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (JULIA_TOKEN)
|
|
New->Type = JULIA_PATTERN;
|
|
Parse_UV_Vect(New->Vals.Fractal.Coord);
|
|
Parse_Comma();
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (MAGNET_TOKEN)
|
|
New->Type = NO_PATTERN;
|
|
New->Vals.Fractal.interior_type = DEFAULT_FRACTAL_INTERIOR_TYPE;
|
|
New->Vals.Fractal.exterior_type = DEFAULT_FRACTAL_EXTERIOR_TYPE;
|
|
New->Vals.Fractal.efactor = DEFAULT_FRACTAL_EXTERIOR_FACTOR;
|
|
New->Vals.Fractal.ifactor = DEFAULT_FRACTAL_INTERIOR_FACTOR;
|
|
i = (int)Parse_Float();
|
|
EXPECT
|
|
CASE (MANDEL_TOKEN)
|
|
switch(i)
|
|
{
|
|
case 1:
|
|
New->Type = MAGNET1M_PATTERN;
|
|
break;
|
|
case 2:
|
|
New->Type = MAGNET2M_PATTERN;
|
|
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;
|
|
break;
|
|
case 2:
|
|
New->Type = MAGNET2J_PATTERN;
|
|
break;
|
|
default:
|
|
Error("Invalid magnet-julia pattern type found. Valid types are 1 and 2.");
|
|
break;
|
|
}
|
|
Parse_UV_Vect(New->Vals.Fractal.Coord);
|
|
Parse_Comma();
|
|
EXIT
|
|
END_CASE
|
|
OTHERWISE
|
|
Error("Invalid magnet pattern found. Valid types are 'mandel' and 'julia'.");
|
|
END_CASE
|
|
END_EXPECT
|
|
New->Vals.Fractal.Iterations = (int)Parse_Float();
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (ONION_TOKEN)
|
|
New->Type = ONION_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPIRAL1_TOKEN)
|
|
New->Type = SPIRAL1_PATTERN;
|
|
New->Vals.Arms = (short)Parse_Float ();
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPIRAL2_TOKEN)
|
|
New->Type = SPIRAL2_PATTERN;
|
|
New->Vals.Arms = (short)Parse_Float ();
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPOTTED_TOKEN)
|
|
New->Type = SPOTTED_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WOOD_TOKEN)
|
|
New->Type = WOOD_PATTERN;
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (GRADIENT_TOKEN)
|
|
New->Type = GRADIENT_PATTERN;
|
|
Parse_Vector (New->Vals.Gradient);
|
|
VNormalizeEq(New->Vals.Gradient);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (RADIAL_TOKEN)
|
|
New->Type = RADIAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CRACKLE_TOKEN)
|
|
New->Type = CRACKLE_PATTERN;
|
|
New->Vals.Crackle.IsSolid = 0;
|
|
New->Vals.Crackle.Form[X] = -1;
|
|
New->Vals.Crackle.Form[Y] = 1;
|
|
New->Vals.Crackle.Form[Z] = 0;
|
|
New->Vals.Crackle.Metric = 2;
|
|
New->Vals.Crackle.Offset = 0;
|
|
New->Vals.Crackle.Dim = 3;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CHECKER_TOKEN)
|
|
New->Type = CHECKER_PATTERN;
|
|
New->Frequency = 0.0;
|
|
END_CASE
|
|
|
|
CASE (OBJECT_TOKEN)
|
|
{
|
|
Parse_Begin();
|
|
vector<ObjectPtr> tempObjects;
|
|
Parse_Bound_Clip(tempObjects, false);
|
|
if(tempObjects.size() != 1)
|
|
Error ("object or object identifier expected.");
|
|
New->Vals.Object = tempObjects[0];
|
|
New->Type = OBJECT_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Parse_End();
|
|
EXIT
|
|
}
|
|
END_CASE
|
|
|
|
CASE (CELLS_TOKEN)
|
|
New->Type = CELLS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BRICK_TOKEN)
|
|
if (New->Type!=BRICK_PATTERN)
|
|
{
|
|
Make_Vector(New->Vals.Brick.Size,8.0,3.0,4.5);
|
|
New->Vals.Brick.Mortar=0.5-EPSILON*2.0;
|
|
New->Type = BRICK_PATTERN;
|
|
}
|
|
New->Frequency = 0.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (HEXAGON_TOKEN)
|
|
New->Type = HEXAGON_PATTERN;
|
|
New->Frequency = 0.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CUBIC_TOKEN) // JN2007: Cubic pattern
|
|
New->Type = CUBIC_PATTERN;
|
|
New->Frequency = 0.0;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WAVES_TOKEN)
|
|
New->Type = WAVES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (RIPPLES_TOKEN)
|
|
New->Type = RIPPLES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (WRINKLES_TOKEN)
|
|
New->Type = WRINKLES_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BUMPS_TOKEN)
|
|
New->Type = BUMPS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (DENTS_TOKEN)
|
|
New->Type = DENTS_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (QUILTED_TOKEN)
|
|
New->Type = QUILTED_PATTERN;
|
|
New->Vals.Quilted.Control0 = 1.0;
|
|
New->Vals.Quilted.Control1 = 1.0;
|
|
New->Frequency = 0.0;
|
|
EXIT
|
|
END_CASE
|
|
/*
|
|
CASE (FACETS_TOKEN)
|
|
if (TPat_Type != NORMAL_TYPE)
|
|
{
|
|
Only_In("facets","normal");
|
|
}
|
|
New->Type = FACETS_PATTERN;
|
|
New->Vals.Facets.Size = 0.1;
|
|
New->Vals.Facets.UseCoords = 0;
|
|
New->Vals.Facets.Metric = 2;
|
|
EXIT
|
|
END_CASE
|
|
*/
|
|
CASE (IMAGE_PATTERN_TOKEN)
|
|
New->Type = IMAGE_PATTERN;
|
|
New->Frequency = 0.0;
|
|
Parse_Image_Pattern (New);
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (PLANAR_TOKEN)
|
|
New->Type = PLANAR_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (BOXED_TOKEN)
|
|
New->Type = BOXED_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (SPHERICAL_TOKEN)
|
|
New->Type = SPHERICAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (CYLINDRICAL_TOKEN)
|
|
New->Type = CYLINDRICAL_PATTERN;
|
|
EXIT
|
|
END_CASE
|
|
|
|
CASE (DENSITY_FILE_TOKEN)
|
|
New->Type = DENSITY_FILE_PATTERN;
|
|
New->Vals.Density_File = Create_Density_File();
|
|
GET(DF3_TOKEN);
|
|
New->Vals.Density_File->Data->Name = Parse_C_String(true);
|
|
{
|
|
IStream *dfile = Locate_File(this, sceneData, ASCIItoUCS2String(New->Vals.Density_File->Data->Name).c_str(), POV_File_Data_DF3, ign, true);
|
|
if(dfile == NULL)
|
|
Error("Cannot read media density file.");
|
|
Read_Density_File(dfile, New->Vals.Density_File);
|
|
}
|
|
EXIT
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
|
|
EXPECT
|
|
CASE (SOLID_TOKEN)
|
|
if (New->Type != CRACKLE_PATTERN )
|
|
Only_In("solid", "crackle");
|
|
New->Vals.Crackle.IsSolid = 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)))
|
|
{
|
|
Only_In("exterior", "mandel, julia or magnet");
|
|
}
|
|
New->Vals.Fractal.exterior_type = (int)Parse_Float();
|
|
if((New->Vals.Fractal.exterior_type < 0) || (New->Vals.Fractal.exterior_type > 6))
|
|
Error("Invalid fractal pattern exterior type. Valid types are 0 to 6.");
|
|
Parse_Comma();
|
|
New->Vals.Fractal.efactor = 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)))
|
|
{
|
|
Only_In("exterior", "mandel, julia or magnet");
|
|
}
|
|
New->Vals.Fractal.interior_type = (int)Parse_Float();
|
|
if((New->Vals.Fractal.interior_type < 0) || (New->Vals.Fractal.interior_type > 6))
|
|
Error("Invalid fractal pattern interior type. Valid types are 0 to 6.");
|
|
Parse_Comma();
|
|
New->Vals.Fractal.ifactor = 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)))
|
|
{
|
|
Only_In("exponent", "mandel or julia");
|
|
}
|
|
|
|
if((New->Type == JULIA_PATTERN) || (New->Type == JULIA3_PATTERN) ||
|
|
(New->Type == JULIA4_PATTERN) || (New->Type == JULIAX_PATTERN))
|
|
{
|
|
New->Vals.Fractal.Exponent = i = (int)Parse_Float();
|
|
switch(i)
|
|
{
|
|
case 2:
|
|
New->Type = JULIA_PATTERN;
|
|
break;
|
|
case 3:
|
|
New->Type = JULIA3_PATTERN;
|
|
break;
|
|
case 4:
|
|
New->Type = JULIA4_PATTERN;
|
|
break;
|
|
default:
|
|
if((i > 4) && (i <= 33))
|
|
{
|
|
New->Type = JULIAX_PATTERN;
|
|
}
|
|
else
|
|
{
|
|
New->Type = JULIA_PATTERN;
|
|
Warning(0, "Invalid julia pattern exponent found. Supported exponents are 2 to 33.\n"
|
|
"Using default exponent 2.");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if((New->Type == MANDEL_PATTERN) || (New->Type == MANDEL3_PATTERN) ||
|
|
(New->Type == MANDEL4_PATTERN) || (New->Type == MANDELX_PATTERN))
|
|
{
|
|
New->Vals.Fractal.Exponent = i = (int)Parse_Float();
|
|
switch(i)
|
|
{
|
|
case 2:
|
|
New->Type = MANDEL_PATTERN;
|
|
break;
|
|
case 3:
|
|
New->Type = MANDEL3_PATTERN;
|
|
break;
|
|
case 4:
|
|
New->Type = MANDEL4_PATTERN;
|
|
break;
|
|
default:
|
|
if((i > 4) && (i <= 33))
|
|
{
|
|
New->Type = MANDELX_PATTERN;
|
|
}
|
|
else
|
|
{
|
|
New->Type = MANDEL_PATTERN;
|
|
Warning(0, "Invalid mandel pattern exponent found. Supported exponents are 2 to 33.\n"
|
|
"Using default exponent 2.");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
END_CASE
|
|
|
|
CASE (COORDS_TOKEN)
|
|
if (New->Type != FACETS_PATTERN )
|
|
Only_In("coords", "facets");
|
|
New->Vals.Facets.UseCoords = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (SIZE_TOKEN)
|
|
if (New->Type != FACETS_PATTERN )
|
|
Only_In("size", "facets");
|
|
New->Vals.Facets.Size = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (METRIC_TOKEN)
|
|
if (New->Type == FACETS_PATTERN )
|
|
{
|
|
Parse_Vector(Local_Vector);
|
|
New->Vals.Facets.Metric = Local_Vector[X];
|
|
}
|
|
else if ( New->Type == CRACKLE_PATTERN )
|
|
{
|
|
Parse_Vector(Local_Vector);
|
|
New->Vals.Crackle.Metric = Local_Vector[X];
|
|
}
|
|
else
|
|
Only_In("metric", "facets or crackle");
|
|
END_CASE
|
|
|
|
CASE (FORM_TOKEN)
|
|
if (New->Type != CRACKLE_PATTERN )
|
|
Only_In("form", "crackle");
|
|
Parse_Vector( New->Vals.Crackle.Form );
|
|
END_CASE
|
|
|
|
CASE (OFFSET_TOKEN)
|
|
if (New->Type != CRACKLE_PATTERN )
|
|
Only_In("offset", "crackle");
|
|
New->Vals.Crackle.Offset = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (TURBULENCE_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Parse_Vector(Local_Turb->Turbulence);
|
|
END_CASE
|
|
/*
|
|
CASE (PIGMENT_MAP_TOKEN)
|
|
if (TPat_Type != PIGMENT_TYPE)
|
|
{
|
|
Only_In("pigment_map","pigment");
|
|
}
|
|
if (New->Type == CHECKER_PATTERN ||
|
|
New->Type == BRICK_PATTERN ||
|
|
New->Type == HEXAGON_PATTERN ||
|
|
New->Type == PLAIN_PATTERN ||
|
|
New->Type == BITMAP_PATTERN)
|
|
Not_With ("pigment_map","this pigment type");
|
|
Destroy_Blend_Map(New->Blend_Map);
|
|
New->Blend_Map = Parse_Blend_Map (PIGMENT_TYPE,New->Type);
|
|
END_CASE
|
|
*/
|
|
CASE (CONTROL0_TOKEN)
|
|
if (New->Type != QUILTED_PATTERN)
|
|
Not_With ("control0","this pattern");
|
|
New->Vals.Quilted.Control0 = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (CONTROL1_TOKEN)
|
|
if (New->Type != QUILTED_PATTERN)
|
|
Not_With ("control1","this pattern");
|
|
New->Vals.Quilted.Control1 = Parse_Float ();
|
|
END_CASE
|
|
|
|
CASE (OCTAVES_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Octaves = (int)Parse_Float();
|
|
if(Local_Turb->Octaves < 1)
|
|
Local_Turb->Octaves = 1;
|
|
if(Local_Turb->Octaves > 10) /* Avoid DOMAIN errors */
|
|
Local_Turb->Octaves = 10;
|
|
END_CASE
|
|
|
|
CASE (OMEGA_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Omega = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (LAMBDA_TOKEN)
|
|
Local_Turb=Check_Turb(&(New->Warps));
|
|
Local_Turb->Lambda = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (FREQUENCY_TOKEN)
|
|
New->Frequency = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (RAMP_WAVE_TOKEN)
|
|
New->Wave_Type = RAMP_WAVE;
|
|
END_CASE
|
|
|
|
CASE (TRIANGLE_WAVE_TOKEN)
|
|
New->Wave_Type = TRIANGLE_WAVE;
|
|
END_CASE
|
|
|
|
CASE (SINE_WAVE_TOKEN)
|
|
New->Wave_Type = SINE_WAVE;
|
|
END_CASE
|
|
|
|
CASE (SCALLOP_WAVE_TOKEN)
|
|
New->Wave_Type = SCALLOP_WAVE;
|
|
END_CASE
|
|
|
|
CASE (CUBIC_WAVE_TOKEN)
|
|
New->Wave_Type = CUBIC_WAVE;
|
|
END_CASE
|
|
|
|
CASE (POLY_WAVE_TOKEN)
|
|
New->Wave_Type = POLY_WAVE;
|
|
New->Exponent = Allow_Float(New->Exponent);
|
|
END_CASE
|
|
|
|
CASE (PHASE_TOKEN)
|
|
New->Phase = Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (NOISE_GENERATOR_TOKEN)
|
|
{
|
|
int noise_generator;
|
|
noise_generator = (int) Parse_Float();
|
|
if (noise_generator < 0 || noise_generator > 3)
|
|
Error ("Value for noise_generator must be 0, 1, 2, or 3.");
|
|
New->Flags |= noise_generator * NOISE_FLAG_1;
|
|
}
|
|
END_CASE
|
|
|
|
CASE (AGATE_TURB_TOKEN)
|
|
if (New->Type != AGATE_PATTERN)
|
|
Not_With ("agate_turb","non-agate");
|
|
New->Vals.Agate_Turb_Scale = Parse_Float();
|
|
Check_Turb(&(New->Warps)); /* agate needs Octaves, Lambda etc. */
|
|
END_CASE
|
|
|
|
CASE (BRICK_SIZE_TOKEN)
|
|
if (New->Type != BRICK_PATTERN)
|
|
Not_With ("brick_size","non-brick");
|
|
Parse_Vector(New->Vals.Brick.Size);
|
|
END_CASE
|
|
|
|
CASE (MORTAR_TOKEN)
|
|
if (New->Type != BRICK_PATTERN)
|
|
Not_With ("mortar","non-brick");
|
|
New->Vals.Brick.Mortar = Parse_Float()-EPSILON*2.0;
|
|
END_CASE
|
|
|
|
CASE (INTERPOLATE_TOKEN)
|
|
if (New->Type != DENSITY_FILE_PATTERN)
|
|
Not_With ("interpolate","non-density_file");
|
|
New->Vals.Density_File->Interpolation = (int)Parse_Float();
|
|
END_CASE
|
|
|
|
CASE (WARP_TOKEN)
|
|
Parse_Warp(&(New->Warps));
|
|
END_CASE
|
|
|
|
CASE (TRANSLATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Translate_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (ROTATE_TOKEN)
|
|
Parse_Vector (Local_Vector);
|
|
Rotate_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (SCALE_TOKEN)
|
|
Parse_Scale_Vector (Local_Vector);
|
|
Scale_Tpattern (New, Local_Vector);
|
|
END_CASE
|
|
|
|
CASE (MATRIX_TOKEN)
|
|
Parse_Matrix(Local_Matrix);
|
|
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
|
|
Transform_Tpattern (New, &Local_Trans);
|
|
END_CASE
|
|
|
|
CASE (TRANSFORM_TOKEN)
|
|
Transform_Tpattern (New, Parse_Transform(&Local_Trans));
|
|
END_CASE
|
|
|
|
CASE (NO_BUMP_SCALE_TOKEN)
|
|
Set_Flag(New,DONT_SCALE_BUMPS_FLAG);
|
|
END_CASE
|
|
|
|
OTHERWISE
|
|
UNGET
|
|
EXIT
|
|
END_CASE
|
|
END_EXPECT
|
|
}
|
|
|
|
}
|