//******************************************************************************
///
/// @file parser/parser.cpp
///
/// This module implements a parser for the scene description files.
///
/// @copyright
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
/// Copyright 1991-2015 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 .
///
/// ----------------------------------------------------------------------------
///
/// 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.
///
/// @endparblock
///
//******************************************************************************
#include
#include
#include
#include
#include
// configparser.h must always be the first POV file included in the parser (pulls in platform config)
#include "parser/configparser.h"
#include "parser/parser.h"
#include "core/material/interior.h"
#include "core/material/normal.h"
#include "core/material/pigment.h"
#include "core/material/texture.h"
#include "core/shape/bezier.h"
#include "core/shape/blob.h"
#include "core/shape/box.h"
#include "core/shape/cone.h"
#include "core/shape/csg.h"
#include "core/shape/disc.h"
#include "core/shape/fractal.h"
#include "core/shape/heightfield.h"
#include "core/shape/isosurface.h"
#include "core/shape/lathe.h"
#include "core/shape/mesh.h"
#include "core/shape/ovus.h"
#include "core/shape/parametric.h"
#include "core/shape/plane.h"
#include "core/shape/polynomial.h"
#include "core/shape/polygon.h"
#include "core/shape/prism.h"
#include "core/shape/quadric.h"
#include "core/shape/sor.h"
#include "core/shape/sphere.h"
#include "core/shape/spheresweep.h"
#include "core/shape/superellipsoid.h"
#include "core/shape/torus.h"
#include "core/shape/triangle.h"
#include "core/shape/truetype.h"
#include "povms/povmsid.h"
#include "backend/bounding/bcyl.h"
#include "backend/bounding/bsphere.h"
#include "backend/colour/colour_old.h"
#include "backend/lighting/photons.h"
#include "backend/lighting/point.h"
#include "backend/lighting/radiosity.h"
#include "backend/lighting/subsurface.h"
#include "backend/math/matrices.h"
#include "backend/math/polysolv.h"
#include "backend/math/splines.h"
#include "backend/math/vector.h"
#include "backend/scene/atmosph.h"
#include "backend/scene/objects.h"
#include "backend/scene/threaddata.h"
#include "backend/support/imageutil.h"
#include "backend/support/octree.h"
#include "backend/vm/fnpovfpu.h"
#include "lightgrp.h"
// this must be the last file included
#include "base/povdebug.h"
namespace pov
{
/*****************************************************************************
* Local preprocessor defines
******************************************************************************/
/* Volume that is considered to be infinite. [DB 9/94] */
const DBL INFINITE_VOLUME = BOUND_HUGE;
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
Parser::Parser(shared_ptr sd, bool useclk, DBL clk) :
SceneTask(new SceneThreadData(sd), boost::bind(&Parser::SendFatalError, this, _1), "Parse", sd),
sceneData(sd),
clockValue(clk),
useClock(useclk),
fnVMContext(sd->functionVM->NewContext(GetParserDataPtr())),
Destroying_Frame(false),
String_Index(0),
String_Buffer_Free(0),
String(NULL),
String2(NULL),
last_progress(0),
Current_Token_Count(0),
token_count(0),
line_count(10),
next_rand(NULL),
Debug_Message_Buffer(sd->backendAddress, sd->frontendAddress, sd->sceneId)
{
pre_init_tokenizer();
if (sceneData->realTimeRaytracing)
mBetaFeatureFlags.realTimeRaytracing = true;
}
/* Parse the file. */
void Parser::Run()
{
int error_line = -1;
int error_col = -1;
UCS2String error_filename(MAX_PATH, 0);
POV_LONG error_pos = -1;
try
{
Init_Random_Generators();
Initialize_Tokenizer();
Brace_Stack = reinterpret_cast(POV_MALLOC(MAX_BRACES*sizeof (TOKEN), "brace stack"));
Brace_Index = 0;
Default_Texture = Create_Texture ();
Default_Texture->Pigment = Create_Pigment();
Default_Texture->Tnormal = NULL;
Default_Texture->Finish = Create_Finish();
Not_In_Default = true;
Ok_To_Declare = true;
//LValue_Ok = false;
Frame_Init ();
for(SceneData::DeclaredVariablesMap::const_iterator i(sceneData->declaredVariables.begin()); i != sceneData->declaredVariables.end(); i++)
{
if(i->second.length() > 0)
{
SYM_ENTRY *Temp_Entry = NULL;
if(i->second[0] == '\"')
{
string tmp(i->second, 1, i->second.length() - 2);
Temp_Entry = Add_Symbol(1, const_cast(i->first.c_str()), STRING_ID_TOKEN);
Temp_Entry->Data = String_Literal_To_UCS2(const_cast(tmp.c_str()), false);
}
else
{
Temp_Entry = Add_Symbol(1, const_cast(i->first.c_str()), FLOAT_ID_TOKEN);
Temp_Entry->Data = Create_Float();
*(reinterpret_cast(Temp_Entry->Data)) = atof(i->second.c_str());
}
}
}
IncludeHeader(sceneData->headerFile);
Parse_Frame();
// post process atmospheric media
for(vector::iterator i(sceneData->atmosphere.begin()); i != sceneData->atmosphere.end(); i++)
i->PostProcess();
// post process global light sources
for(size_t i = 0; i < sceneData->lightSources.size(); i++)
{
sceneData->lightSources[i]->index = i;
sceneData->lightSources[i]->lightGroupLight = false;
}
// post process local light sources
for(size_t i = 0; i < sceneData->lightGroupLightSources.size(); i++)
{
sceneData->lightGroupLightSources[i]->index = i;
sceneData->lightGroupLightSources[i]->lightGroupLight = true;
}
}
catch(std::bad_alloc&)
{
try
{
if (Token.FileHandle != NULL)
{
// take a (local) copy of error location prior to freeing token data
// NB error_filename has been pre-allocated for strings up to _MAX_PATH
error_filename = Token.FileHandle->name();
error_line = Token.Token_File_Pos.lineno;
error_col = Token.Token_Col_No;
error_pos = Token.FileHandle->tellg().offset;
}
// free up some memory before proceeding with error notification.
Terminate_Tokenizer();
Destroy_Textures(Default_Texture);
Default_Texture = NULL;
POV_FREE (Brace_Stack);
Brace_Stack = NULL;
Destroy_Random_Generators();
if (error_line != -1)
messageFactory.ErrorAt(POV_EXCEPTION_CODE(kOutOfMemoryErr), error_filename.c_str(), error_line, error_col, error_pos, "Out of memory.");
else
Error("Out of memory.");
}
catch (std::bad_alloc&)
{
// ran out of memory during processing of bad_alloc above ...
// not much we can do except return
return;
}
catch(...)
{
// other exceptions are OK to re-throw here (in particular, Error/ErrorAt will throw one)
throw;
}
}
// validate scene contents
if(sceneData->objects.empty())
Warning("No objects in scene.");
Terminate_Tokenizer();
Destroy_Textures(Default_Texture);
POV_FREE (Brace_Stack);
Destroy_Random_Generators();
Default_Texture = NULL;
Brace_Stack = NULL;
// Check for experimental features
char str[512] = "";
if(mExperimentalFlags.backsideIllumination)
strcat(str, str [0] ? ", backside illumination" : "backside illumination");
if(mExperimentalFlags.functionHf)
strcat(str, str [0] ? ", function '.hf'" : "function '.hf'");
if(mExperimentalFlags.meshCamera)
strcat(str, str [0] ? ", mesh camera" : "mesh camera");
if(mExperimentalFlags.slopeAltitude)
strcat(str, str [0] ? ", slope pattern altitude" : "slope pattern altitude");
if(mExperimentalFlags.spline)
strcat(str, str [0] ? ", spline" : "spline");
if(mExperimentalFlags.subsurface)
strcat(str, str [0] ? ", subsurface light transport" : "subsurface light transport");
if(mExperimentalFlags.tiff)
strcat(str, str [0] ? ", TIFF image support" : "TIFF image support");
if (str[0] != '\0')
Warning("This rendering uses the following experimental feature(s): %s.\n"
"The design and implementation of these features is likely to change in future\n"
"versions of POV-Ray. Backward compatibility with the current implementation is\n"
"not guaranteed.",
str);
// Check for beta features
str[0] = '\0';
if(mBetaFeatureFlags.videoCapture)
strcat(str, str [0] ? ", video capture" : "video capture");
if(mBetaFeatureFlags.realTimeRaytracing)
strcat(str, str [0] ? ", real-time raytracing render loop" : "real-time raytracing render loop");
if (str[0] != '\0')
Warning("This rendering uses the following beta-test feature(s): %s.\n"
"The implementation of these features is likely to change or be completely\n"
"removed in subsequent beta-test versions of POV-Ray. There is no guarantee\n"
"that they will be available in the next full release version.\n",
str);
if ((sceneData->bspMaxDepth != 0) ||
(sceneData->bspObjectIsectCost != 0.0f) || (sceneData->bspBaseAccessCost != 0.0f) ||
(sceneData->bspChildAccessCost != 0.0f) || (sceneData->bspMissChance != 0.0f))
{
Warning("You have overridden a default BSP tree cost constant. Note that these "
"INI settings may be removed or changed prior to the final 3.7 release.\n");
}
// TODO FIXME - review whole if-statement and line after it below [trf]
// we set this before resetting languageVersion since there's nothing to
// be gained from disabling the defaulting of the noise generator to
// something other than compatibilty mode.
if (sceneData->explicitNoiseGenerator == false)
sceneData->noiseGenerator = (sceneData->EffectiveLanguageVersion() < 350 ?
kNoiseGen_Original : kNoiseGen_RangeCorrected);
if((sceneData->gammaMode != kPOVList_GammaMode_AssumedGamma36) && (sceneData->gammaMode != kPOVList_GammaMode_AssumedGamma37))
{
if (sceneData->EffectiveLanguageVersion() < 370)
{
sceneData->gammaMode = kPOVList_GammaMode_None;
sceneData->workingGamma.reset();
sceneData->workingGammaToSRGB.reset();
Warning("assumed_gamma not specified, so gamma_correction is turned off for compatibility\n"
"with this pre POV-Ray 3.7 scene. See the documentation for more details.");
}
else
{
sceneData->gammaMode = kPOVList_GammaMode_AssumedGamma37Implied;
sceneData->workingGamma = GetGammaCurve(DEFAULT_WORKING_GAMMA_TYPE, DEFAULT_WORKING_GAMMA);
sceneData->workingGammaToSRGB = TranscodingGammaCurve::Get(sceneData->workingGamma, SRGBGammaCurve::Get());
PossibleError("assumed_gamma not specified in this POV-Ray 3.7 or later scene. Future\n"
"versions of POV-Ray may consider this a fatal error. To avoid this\n"
"warning, explicitly specify 'assumed_gamma " DEFAULT_WORKING_GAMMA_TEXT "' in the global_settings\n"
"section. See the documentation for more details.");
}
}
if(sceneData->EffectiveLanguageVersion() < 350)
{
Warning("The scene finished parsing with a language version set to 3.1 or earlier. Full\n"
"backward compatibility with scenes requiring support for bugs in POV-Ray\n"
"version 3.1 or earlier is not guaranteed. Please use POV-Ray 3.5 or earlier if\n"
"your scene depends on rendering defects caused by these bugs.");
sceneData->languageVersion = 350;
}
if(sceneData->languageVersionLate)
{
Warning("This scene had other declarations preceding the first #version directive.\n"
"Please be aware that as of POV-Ray 3.7, unless already specified via an INI\n"
"option, a #version is expected as the first declaration in a scene file. If\n"
"this is not done, POV-Ray may apply compatibility settings to some features\n"
"that are intended to make pre-3.7 scenes render as designed. You are strongly\n"
"encouraged to add a #version statement to the scene to make your intent clear.\n"
"Future versions of POV-Ray may make the presence of a #version mandatory.");
}
else if(sceneData->languageVersionSet == false)
{
Warning("This scene did not contain a #version directive. Please be aware that as of\n"
"POV-Ray 3.7, unless already specified via an INI option, a #version is\n"
"expected as the first declaration in a scene file. POV-Ray may apply settings\n"
"to some features that are intended to maintain compatibility with pre-3.7\n"
"scenes. You are strongly encouraged to add a #version statement to the scene\n"
"to make your intent clear. Future versions of POV-Ray may make the presence of\n"
"a #version statement mandatory.");
}
sceneData->parsedMaxTraceLevel = Max_Trace_Level;
if (sceneData->clocklessAnimation == true)
{
if (sceneData->cameras.size() < 2)
{
Warning("Need at least two cameras for a clockless animation loop - treating\nscene as single frame.");
sceneData->clocklessAnimation = false;
}
else
{
Warning("Clockless animation: total of %d cameras will be used.", sceneData->cameras.size());
sceneData->parsedCamera = sceneData->cameras[0];
}
}
if (sceneData->radiositySettings.pretraceEnd > sceneData->radiositySettings.pretraceStart)
Error("Radiosity pretrace end must be smaller than or equal to pretrace start.");
if (sceneData->radiositySettings.minimumReuse > sceneData->radiositySettings.maximumReuse * 0.5)
{
if (!sceneData->radiositySettings.minimumReuseSet)
{
sceneData->radiositySettings.minimumReuse = sceneData->radiositySettings.maximumReuse * 0.5;
Warning("Radiosity maximum_reuse should be significantly larger than minimum_reuse.\n"
"Decreasing minimum_reuse to %lf instead of the default.",
sceneData->radiositySettings.minimumReuse);
}
else if (!sceneData->radiositySettings.maximumReuseSet)
{
sceneData->radiositySettings.maximumReuse = sceneData->radiositySettings.minimumReuse * 2.0;
Warning("Radiosity maximum_reuse should be significantly larger than minimum_reuse.\n"
"Increasing maximum_reuse to %lf instead of the default.",
sceneData->radiositySettings.maximumReuse);
}
else if (sceneData->radiositySettings.minimumReuse >= sceneData->radiositySettings.maximumReuse)
{
Error("Radiosity maximum_reuse must be larger than minimum_reuse.\n");
}
else
{
Warning("Radiosity maximum_reuse should be significantly larger than minimum_reuse.\n");
}
}
}
void Parser::Cleanup()
{
sceneData->functionVM->DeleteContext(fnVMContext);
// TODO FIXME - cleanup [trf]
Terminate_Tokenizer();
Destroy_Textures(Default_Texture);
Default_Texture = NULL;
if (Brace_Stack != NULL)
POV_FREE (Brace_Stack);
Brace_Stack = NULL;
Destroy_Random_Generators();
}
void Parser::Stopped()
{
RenderBackend::SendSceneFailedResult(sceneData->sceneId, kUserAbortErr, sceneData->frontendAddress);
}
void Parser::Finish()
{
Cleanup();
GetParserDataPtr()->timeType = SceneThreadData::kParseTime;
GetParserDataPtr()->realTime = ConsumedRealTime();
GetParserDataPtr()->cpuTime = ConsumedCPUTime();
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
/* Set up the fields in the frame to default values. */
void Parser::Frame_Init()
{
Destroying_Frame = false;
sceneData->parsedCamera = Default_Camera;
sceneData->lightSources.clear();
sceneData->atmosphereIOR = 1.0;
sceneData->atmosphereDispersion = 1.0;
// TODO FIXME Frame.Antialias_Threshold = opts.Antialias_Threshold;
/* Init atmospheric stuff. [DB 12/94] */
sceneData->fog = NULL;
sceneData->rainbow = NULL;
sceneData->skysphere = NULL;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::Destroy_Frame()
{
FOG *Fog, *Next_Fog;
RAINBOW *Rainbow, *Next_Rainbow;
// This is necessary as a user who hits CANCEL during any IO performed
// by this routine (e.g. Destroy_Object(), which can complain about
// isosurface max_gradient), will cause this routine to be entered again
// before the relevent data member has been set to NULL (this is able
// to happen since cancel will invoke a longjmp on most platforms).
// This causes the currently-executing segment to be destroyed twice,
// which is a Bad Thing(tm). [CJC 11/01]
if (Destroying_Frame)
return;
Destroying_Frame = true;
/* Destroy fogs. [DB 12/94] */
for (Fog = sceneData->fog; Fog != NULL;)
{
Next_Fog = Fog->Next;
Destroy_Fog(Fog);
Fog = Next_Fog;
}
sceneData->fog = NULL;
/* Destroy rainbows. [DB 12/94] */
for (Rainbow = sceneData->rainbow; Rainbow != NULL;)
{
Next_Rainbow = Rainbow->Next;
Destroy_Rainbow(Rainbow);
Rainbow = Next_Rainbow;
}
sceneData->rainbow = NULL;
/* Destroy skysphere. [DB 12/94] */
Destroy_Skysphere(sceneData->skysphere);
sceneData->skysphere = NULL;
if(!sceneData->objects.empty())
{
Destroy_Object(sceneData->objects);
sceneData->objects.clear();
sceneData->lightSources.clear();
}
if(!sceneData->lightGroupLightSources.empty())
{
for(vector::iterator i = sceneData->lightGroupLightSources.begin(); i != sceneData->lightGroupLightSources.end(); i++)
Destroy_Object(*i);
sceneData->lightGroupLightSources.clear();
}
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::Parse_Begin ()
{
const char *front;
if(++Brace_Index >= MAX_BRACES)
{
Warning("Too many nested '{' braces.");
Brace_Index--;
}
Brace_Stack[Brace_Index]=Token.Token_Id;
Get_Token();
if(Token.Token_Id == LEFT_CURLY_TOKEN)
{
return;
}
front = Get_Token_String(Brace_Stack[Brace_Index]);
Found_Instead_Error("Missing { after", front);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::Parse_End ()
{
const char *front;
Get_Token();
if(Token.Token_Id == RIGHT_CURLY_TOKEN)
{
if(--Brace_Index < 0)
{
Warning("Possible '}' brace missmatch.");
Brace_Index = 0;
}
return;
}
front = Get_Token_String (Brace_Stack[Brace_Index]);
Found_Instead_Error("No matching } in", front);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Bicubic_Patch ()
{
BicubicPatch *Object;
int i, j;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return (reinterpret_cast(Object));
}
Object = new BicubicPatch();
EXPECT
CASE_FLOAT
VersionWarning(150, "Should use keywords for bicubic parameters.");
Object->Patch_Type = (int)Parse_Float();
if (Object->Patch_Type == 2 ||
Object->Patch_Type == 3)
{
Object->Flatness_Value = Parse_Float();
}
else
{
Object->Flatness_Value = 0.1;
}
Object->U_Steps = (int)Parse_Float();
Object->V_Steps = (int)Parse_Float();
EXIT
END_CASE
CASE (TYPE_TOKEN)
Object->Patch_Type = (int)Parse_Float();
END_CASE
CASE (FLATNESS_TOKEN)
Object->Flatness_Value = Parse_Float();
END_CASE
CASE (V_STEPS_TOKEN)
Object->V_Steps = (int)Parse_Float();
END_CASE
CASE (U_STEPS_TOKEN)
Object->U_Steps = (int)Parse_Float();
END_CASE
CASE (ACCURACY_TOKEN)
Object->accuracy = Parse_Float();
END_CASE
CASE(UV_VECTORS_TOKEN)
/* Store 4 ST coords for quadrilateral */
Parse_UV_Vect(Object->ST[0]); Parse_Comma();
Parse_UV_Vect(Object->ST[1]); Parse_Comma();
Parse_UV_Vect(Object->ST[2]); Parse_Comma();
Parse_UV_Vect(Object->ST[3]);
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if (Object->Patch_Type > 1)
{
Object->Patch_Type = 1;
Warning("Patch type no longer supported. Using type 1.");
}
if ((Object->Patch_Type < 0) || (Object->Patch_Type > MAX_PATCH_TYPE))
{
Error("Undefined bicubic patch type.");
}
Parse_Comma();
for (i=0;i<4;i++)
{
for (j=0;j<4;j++)
{
Parse_Vector(Object->Control_Points[i][j]);
if(!((i == 3) && (j == 3)))
Parse_Comma();
}
}
Object->Precompute_Patch_Values(); /* interpolated mesh coords */
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Blob
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Jul 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Blob()
{
int npoints;
DBL threshold;
Vector3d Axis, Base, Apex;
Blob *Object;
Blob_List_Struct *blob_components, *blob_component;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return (reinterpret_cast(Object));
}
Object = new Blob();
blob_components = NULL;
npoints = 0;
threshold = 1.0;
EXPECT
CASE (THRESHOLD_TOKEN)
threshold = Parse_Float();
END_CASE
/*************************************************************************
* Read sperical component (old syntax).
*************************************************************************/
CASE (COMPONENT_TOKEN)
blob_component = Object->Create_Blob_List_Element();
blob_component->elem.Type = BLOB_SPHERE;
blob_component->elem.c[2] = Parse_Float();
Parse_Comma();
blob_component->elem.rad2 = Parse_Float();
Parse_Comma();
blob_component->elem.rad2 = Sqr(blob_component->elem.rad2);
Parse_Vector(blob_component->elem.O);
/* Next component. */
blob_component->next = blob_components;
blob_components = blob_component;
npoints++;
END_CASE
/*************************************************************************
* Read sperical component (new syntax).
*************************************************************************/
CASE (SPHERE_TOKEN)
blob_component = Object->Create_Blob_List_Element();
blob_component->elem.Type = BLOB_SPHERE;
Parse_Begin();
Parse_Vector(blob_component->elem.O);
Parse_Comma();
blob_component->elem.rad2 = Parse_Float();
blob_component->elem.rad2 = Sqr(blob_component->elem.rad2);
Parse_Comma();
ALLOW(STRENGTH_TOKEN)
blob_component->elem.c[2] = Parse_Float();
Parse_Blob_Element_Mods(&blob_component->elem);
/* Next component. */
blob_component->next = blob_components;
blob_components = blob_component;
npoints++;
END_CASE
/*************************************************************************
* Read cylindrical component.
*************************************************************************/
CASE (CYLINDER_TOKEN)
blob_component = Object->Create_Blob_List_Element();
blob_component->elem.Type = BLOB_CYLINDER;
blob_component->elem.Trans = Create_Transform();
Parse_Begin();
Parse_Vector(Base);
Parse_Comma();
Parse_Vector(Apex);
Parse_Comma();
blob_component->elem.rad2 = Parse_Float();
blob_component->elem.rad2 = Sqr(blob_component->elem.rad2);
Parse_Comma();
ALLOW(STRENGTH_TOKEN)
blob_component->elem.c[2] = Parse_Float();
/* Calculate cylinder's coordinate system. */
Axis = Apex - Base;
blob_component->elem.len = Axis.length();
if (blob_component->elem.len < EPSILON)
{
Error("Degenerate cylindrical component in blob.");
}
Axis /= blob_component->elem.len;
Compute_Coordinate_Transform(blob_component->elem.Trans, Base, Axis, 1.0, 1.0);
Parse_Blob_Element_Mods(&blob_component->elem);
/* Next component. */
blob_component->next = blob_components;
blob_components = blob_component;
npoints++;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Object->Create_Blob_Element_Texture_List(blob_components, npoints);
Parse_Object_Mods(reinterpret_cast(Object));
/* The blob's texture has to be processed before Make_Blob() is called. */
Post_Textures(Object->Texture);
/* Finally, process the information */
int components = Object->Make_Blob(threshold, blob_components, npoints, GetParserDataPtr());
if (components > sceneData->Max_Blob_Components)
sceneData->Max_Blob_Components = components;
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Blob_Element_Mods
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Sep 1994 : Creation.
*
******************************************************************************/
void Parser::Parse_Blob_Element_Mods(Blob_Element *Element)
{
Vector3d Local_Vector;
MATRIX Local_Matrix;
TRANSFORM Local_Trans;
TEXTURE *Local_Texture;
EXPECT
CASE (TRANSLATE_TOKEN)
Parse_Vector (Local_Vector);
Blob::Translate_Blob_Element (Element, Local_Vector);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (Local_Vector);
Blob::Rotate_Blob_Element (Element, Local_Vector);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector (Local_Vector);
Blob::Scale_Blob_Element (Element, Local_Vector);
END_CASE
CASE (TRANSFORM_TOKEN)
Blob::Transform_Blob_Element (Element, Parse_Transform(&Local_Trans));
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix (Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
Blob::Transform_Blob_Element (Element, &Local_Trans);
END_CASE
CASE (TEXTURE_TOKEN)
Parse_Begin ();
Local_Texture = Parse_Texture();
Parse_End ();
Link_Textures(&Element->Texture, Local_Texture);
END_CASE
CASE3 (PIGMENT_TOKEN, TNORMAL_TOKEN, FINISH_TOKEN)
if (Element->Texture == NULL)
{
Element->Texture = Copy_Textures(Default_Texture);
}
else
{
if (Element->Texture->Type != PLAIN_PATTERN)
{
Link_Textures(&Element->Texture, Copy_Textures(Default_Texture));
}
}
UNGET
EXPECT
CASE (PIGMENT_TOKEN)
Parse_Begin ();
Parse_Pigment(&Element->Texture->Pigment);
Parse_End ();
END_CASE
CASE (TNORMAL_TOKEN)
Parse_Begin ();
Parse_Tnormal(&Element->Texture->Tnormal);
Parse_End ();
END_CASE
CASE (FINISH_TOKEN)
Parse_Finish(&Element->Texture->Finish);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_End();
/* Postprocess to make sure that HAS_FILTER will be set correctly. */
Post_Textures(Element->Texture);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Box ()
{
Box *Object;
DBL temp;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Box();
Parse_Vector(Object->bounds[0]); Parse_Comma();
Parse_Vector(Object->bounds[1]);
if (Object->bounds[0][X] > Object->bounds[1][X]) {
temp = Object->bounds[0][X];
Object->bounds[0][X] = Object->bounds[1][X];
Object->bounds[1][X] = temp;
}
if (Object->bounds[0][Y] > Object->bounds[1][Y]) {
temp = Object->bounds[0][Y];
Object->bounds[0][Y] = Object->bounds[1][Y];
Object->bounds[1][Y] = temp;
}
if (Object->bounds[0][Z] > Object->bounds[1][Z]) {
temp = Object->bounds[0][Z];
Object->bounds[0][Z] = Object->bounds[1][Z];
Object->bounds[1][Z] = temp;
}
Object->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
void Parser::Parse_Mesh_Camera (Camera& Cam)
{
Cam.Type = MESH_CAMERA;
Parse_Begin ();
// Get the rays per pixel
Cam.Rays_Per_Pixel = (unsigned int) Parse_Float();
if (Cam.Rays_Per_Pixel == 0)
Error("Rays per pixel may not be 0");
// Now get the distribution type.
Cam.Face_Distribution_Method = (unsigned int) Parse_Float();
if (Cam.Face_Distribution_Method > 3)
Error("Unrecognized distribution method");
if (Cam.Face_Distribution_Method == 2 || Cam.Face_Distribution_Method == 3)
if (Cam.Rays_Per_Pixel != 1)
Error("Rays per pixel must be 1 for distribution method #2 or #3");
// Now the optional maximum ray length
Cam.Max_Ray_Distance = Allow_Float(0.0);
EXPECT
CASE2 (MESH_TOKEN, MESH2_TOKEN)
Cam.Meshes.push_back(Parse_Mesh());
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
ALLOW(SMOOTH_TOKEN);
Cam.Smooth = Token.Token_Id == SMOOTH_TOKEN;
if (Cam.Smooth && Cam.Face_Distribution_Method != 3)
Error("Smooth can only be used with distribution method #3");
Parse_End ();
if (Cam.Meshes.size() == 0)
Expectation_Error("mesh or mesh2");
if ((Cam.Face_Distribution_Method) == 0)
if (Cam.Rays_Per_Pixel > Cam.Meshes.size())
Error("Rays per pixel must be <= number of meshes for distribution method #0");
unsigned int faces = 0;
for (std::vector::const_iterator it = Cam.Meshes.begin(); it != Cam.Meshes.end(); it++)
Cam.Mesh_Index.push_back(faces += static_cast(*it)->Data->Number_Of_Triangles);
if (Cam.Face_Distribution_Method == 3)
{
if (Cam.Meshes.size() > 1)
Warning("Additional meshes after the first are ignored for distribution method #3");
// build a 10 row and 10 column index relating faces to UV co-ordinates. each face is represented
// by a single bit at each node of the index. to determine which faces cover a given pair of
// co-ordinates, we just need to AND the two columns together.
const Mesh *mesh = static_cast(Cam.Meshes[0]);
unsigned int size = (mesh->Data->Number_Of_Triangles + 31) / 32;
for (int i = 0; i < 10; i++) {
Cam.U_Xref[i].resize(size);
Cam.V_Xref[i].resize(size);
}
Mesh_Triangle_Struct *tr(mesh->Data->Triangles);
for (int i = 0, idx = 0, bit = 1; i < mesh->Data->Number_Of_Triangles; i++, tr++)
{
int P1u(mesh->Data->UVCoords[tr->UV1][U] * 10);
int P2u(mesh->Data->UVCoords[tr->UV2][U] * 10);
int P3u(mesh->Data->UVCoords[tr->UV3][U] * 10);
int P1v(mesh->Data->UVCoords[tr->UV1][V] * 10);
int P2v(mesh->Data->UVCoords[tr->UV2][V] * 10);
int P3v(mesh->Data->UVCoords[tr->UV3][V] * 10);
int minU = min(min(P1u, min(P2u, P3u)), 9);
int minV = min(min(P1v, min(P2v, P3v)), 9);
int maxU = min(max(P1u, max(P2u, P3u)), 9);
int maxV = min(max(P1v, max(P2v, P3v)), 9);
for (int u = minU; u <= maxU; u++)
Cam.U_Xref[u][idx] |= bit;
for (int v = minV; v <= maxV; v++)
Cam.V_Xref[v][idx] |= bit;
if ((bit <<= 1) == 0)
{
idx++;
bit = 1;
}
}
}
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::Parse_Camera (Camera& Cam)
{
int i;
DBL Direction_Length = 1.0, Up_Length, Right_Length, Handedness;
DBL k1, k2, k3;
Vector3d tempv;
MATRIX Local_Matrix;
TRANSFORM Local_Trans;
bool only_mods = false;
Parse_Begin ();
EXPECT
CASE (CAMERA_ID_TOKEN)
Cam = *reinterpret_cast(Token.Data);
if (sceneData->EffectiveLanguageVersion() >= 350)
only_mods = true;
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Camera& New = Cam;
if ((sceneData->EffectiveLanguageVersion() >= 350) && (only_mods == true))
{
// keep a copy and clear it because this is a copy of a camera
// and this will prevent that transforms are applied twice [trf]
TRANSFORM Backup_Trans = *New.Trans;
Destroy_Transform(New.Trans);
New.Trans = Create_Transform();
EXPECT
CASE (TRANSLATE_TOKEN)
Parse_Vector (tempv);
Compute_Translation_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (tempv);
Compute_Rotation_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector(tempv);
Compute_Scaling_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (TRANSFORM_TOKEN)
Parse_Transform(&Local_Trans);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix(Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
// apply camera transformations
New.Transform(New.Trans);
Compose_Transforms(&Backup_Trans, New.Trans);
}
else if (sceneData->EffectiveLanguageVersion() >= 350)
{
/*
* The camera statement in version 3.5 is a tiny bit more restrictive
* than in previous versions (Note: Backward compatibility is available
* with the version switch!). It will always apply camera modifiers in
* the same order, regardless of the order in which they appeared in the
* camera statement. The order is as follows:
*
* right
* direction
* angle (depends on right, changes direction-length)
* up
* sky
* location
* look_at (depends on location, right, direction, up, sky, changes right, up, direction)
* focal_point (depends on location)
*
* VERIFY: Is there a need to modify look_at to consider angle, right, up and/or direction??? [trf]
* VERIFY: Is there a need to modify angle to consider direction??? [trf]
*/
bool had_angle = false, had_up = false, had_right = false;
Vector3d old_look_at, old_up, old_right, old_focal_point;
DBL old_angle;
old_look_at = New.Look_At;
New.Look_At = Vector3d(HUGE_VAL);
old_up = New.Up;
New.Up = Vector3d(HUGE_VAL);
old_right = New.Right;
New.Right = Vector3d(HUGE_VAL);
old_focal_point = New.Focal_Point;
New.Focal_Point = Vector3d(HUGE_VAL);
old_angle = New.Angle;
New.Angle = HUGE_VAL;
EXPECT
CASE (PERSPECTIVE_TOKEN)
New.Type = PERSPECTIVE_CAMERA;
END_CASE
CASE (ORTHOGRAPHIC_TOKEN)
New.Type = ORTHOGRAPHIC_CAMERA;
END_CASE
CASE (FISHEYE_TOKEN)
New.Type = FISHEYE_CAMERA;
END_CASE
CASE (ULTRA_WIDE_ANGLE_TOKEN)
New.Type = ULTRA_WIDE_ANGLE_CAMERA;
END_CASE
CASE (OMNIMAX_TOKEN)
New.Type = OMNIMAX_CAMERA;
END_CASE
CASE (PANORAMIC_TOKEN)
New.Type = PANORAMIC_CAMERA;
END_CASE
CASE (SPHERICAL_TOKEN)
New.Type = SPHERICAL_CAMERA;
END_CASE
CASE (CYLINDER_TOKEN)
i = (int)Parse_Float();
switch (i)
{
case 1: New.Type = CYL_1_CAMERA; break;
case 2: New.Type = CYL_2_CAMERA; break;
case 3: New.Type = CYL_3_CAMERA; break;
case 4: New.Type = CYL_4_CAMERA; break;
default: Error("Invalid cylinder camera type, valid are types 1 to 4."); break;
}
END_CASE
CASE (MESH_CAMERA_TOKEN)
mExperimentalFlags.meshCamera = true;
Parse_Mesh_Camera(New);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
switch(New.Type)
{
case PERSPECTIVE_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE2(SPHERICAL_TOKEN, CYLINDER_TOKEN)
Expectation_Error("perspective camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case ORTHOGRAPHIC_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Allow_Float(0.0);
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(PERSPECTIVE_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE2(SPHERICAL_TOKEN, CYLINDER_TOKEN)
Expectation_Error("orthographic camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case FISHEYE_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE3(SPHERICAL_TOKEN, CYLINDER_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("fisheye camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case ULTRA_WIDE_ANGLE_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE3(SPHERICAL_TOKEN, CYLINDER_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("ultra_wide_angle camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case OMNIMAX_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, PANORAMIC_TOKEN)
CASE3(SPHERICAL_TOKEN, CYLINDER_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("omnimax camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case PANORAMIC_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE5(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN)
CASE3(SPHERICAL_TOKEN, CYLINDER_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("panoramic camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case CYL_1_CAMERA:
case CYL_2_CAMERA:
case CYL_3_CAMERA:
case CYL_4_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
END_CASE
CASE6(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE2(SPHERICAL_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("cylinder camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case SPHERICAL_CAMERA:
EXPECT
CASE (ANGLE_TOKEN)
New.H_Angle = Parse_Float();
if (New.H_Angle < 0.0)
Error("Negative horizontal angle not allowed.");
Parse_Comma();
New.V_Angle = Allow_Float(New.H_Angle * 0.5);
if (New.V_Angle < 0.0)
Error("Negative vertical angle not allowed.");
END_CASE
CASE6(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE2(CYLINDER_TOKEN, MESH_CAMERA_TOKEN)
Expectation_Error("spherical camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
case MESH_CAMERA:
EXPECT
CASE6(PERSPECTIVE_TOKEN, ORTHOGRAPHIC_TOKEN, FISHEYE_TOKEN, ULTRA_WIDE_ANGLE_TOKEN, OMNIMAX_TOKEN, PANORAMIC_TOKEN)
CASE2(CYLINDER_TOKEN, SPHERICAL_TOKEN)
Expectation_Error("mesh camera modifier");
END_CASE
OTHERWISE
UNGET
if(Parse_Camera_Mods(New) == false)
EXIT
END_CASE
END_EXPECT
break;
}
// handle "up"
if (New.Up[X] == HUGE_VAL)
{
New.Up = old_up; // restore default up
}
else
had_up = true;
// handle "right"
if (New.Right[X] == HUGE_VAL)
{
New.Right = old_right; // restore default right
}
else
had_right = true;
// apply "angle"
if (New.Angle != HUGE_VAL)
{
if ((New.Type == PERSPECTIVE_CAMERA) || (New.Type == ORTHOGRAPHIC_CAMERA))
{
if (New.Angle >= 180.0)
Error("Viewing angle has to be smaller than 180 degrees.");
if (New.Angle > 0.0)
{
New.Direction.normalize();
Right_Length = New.Right.length();
Direction_Length = Right_Length / tan(New.Angle * M_PI_360)/2.0;
New.Direction *= Direction_Length;
}
}
had_angle = true;
}
else
New.Angle = old_angle; // restore default angle
// apply "look_at"
if (New.Look_At[X] != HUGE_VAL)
{
Direction_Length = New.Direction.length();
Up_Length = New.Up.length();
Right_Length = New.Right.length();
tempv = cross(New.Up, New.Direction);
Handedness = dot(tempv, New.Right);
New.Direction = New.Look_At - New.Location;
// Check for zero length direction vector.
if (New.Direction.lengthSqr() < EPSILON)
Error("Camera location and look_at point must be different.");
New.Direction.normalize();
// Save Right vector
tempv = New.Right;
New.Right = cross(New.Sky, New.Direction);
// Avoid DOMAIN error (from Terry Kanakis)
if((fabs(New.Right[X]) < EPSILON) &&
(fabs(New.Right[Y]) < EPSILON) &&
(fabs(New.Right[Z]) < EPSILON))
{
Warning("Camera location to look_at direction and sky direction should be different.\n"
"Using default/supplied right vector instead.");
// Restore Right vector
New.Right = tempv;
}
New.Right.normalize();
New.Up = cross(New.Direction, New.Right);
New.Direction *= Direction_Length;
if (Handedness > 0.0)
{
New.Right *= Right_Length;
}
else
{
New.Right *= -Right_Length;
}
New.Up *= Up_Length;
}
else
New.Look_At = old_look_at; // restore default look_at
// apply "orthographic"
if (New.Type == ORTHOGRAPHIC_CAMERA)
{
// only if neither up nor right have been specified
// or if angle has been specified regardless if up or right have been specified
if (((had_up == false) && (had_right == false)) || (had_angle == true))
{
// resize right and up vector to get the same image
// area as we get with the perspective camera
tempv = New.Look_At - New.Location;
k1 = tempv.length();
k2 = New.Direction.length();
if ((k1 > EPSILON) && (k2 > EPSILON))
{
New.Right *= (k1 / k2);
New.Up *= (k1 / k2);
}
}
}
// apply "focal_point"
if (New.Focal_Point[X] != HUGE_VAL)
{
tempv = New.Focal_Point - New.Location;
New.Focal_Distance = tempv.length();
}
else
New.Focal_Point = old_focal_point; // restore default focal_point
// apply camera transformations
New.Transform(New.Trans);
}
else // old style syntax [mesh camera not supported]
{
EXPECT
CASE (PERSPECTIVE_TOKEN)
New.Type = PERSPECTIVE_CAMERA;
END_CASE
CASE (ORTHOGRAPHIC_TOKEN)
New.Type = ORTHOGRAPHIC_CAMERA;
// resize right and up vector to get the same image
// area as we get with the perspective camera
tempv = New.Look_At - New.Location;
k1 = tempv.length();
k2 = New.Direction.length();
if ((k1 > EPSILON) && (k2 > EPSILON))
{
New.Right *= (k1 / k2);
New.Up *= (k1 / k2);
}
END_CASE
CASE (FISHEYE_TOKEN)
New.Type = FISHEYE_CAMERA;
END_CASE
CASE (ULTRA_WIDE_ANGLE_TOKEN)
New.Type = ULTRA_WIDE_ANGLE_CAMERA;
END_CASE
CASE (OMNIMAX_TOKEN)
New.Type = OMNIMAX_CAMERA;
END_CASE
CASE (PANORAMIC_TOKEN)
New.Type = PANORAMIC_CAMERA;
END_CASE
CASE (MESH_CAMERA_TOKEN)
Error("This camera type not supported for language version < 3.5");
END_CASE
CASE (CYLINDER_TOKEN)
i = (int)Parse_Float();
switch (i)
{
case 1: New.Type = CYL_1_CAMERA; break;
case 2: New.Type = CYL_2_CAMERA; break;
case 3: New.Type = CYL_3_CAMERA; break;
case 4: New.Type = CYL_4_CAMERA; break;
}
END_CASE
CASE (ANGLE_TOKEN)
New.Angle = Parse_Float();
if (New.Angle < 0.0)
Error("Negative viewing angle.");
if (New.Type == PERSPECTIVE_CAMERA)
{
if (New.Angle >= 180.0)
Error("Viewing angle has to be smaller than 180 degrees.");
New.Direction.normalize();
Right_Length = New.Right.length();
Direction_Length = Right_Length / tan(New.Angle * M_PI_360)/2.0;
New.Direction *= Direction_Length;
}
END_CASE
CASE (TNORMAL_TOKEN)
Parse_Begin ();
Parse_Tnormal(&(New.Tnormal));
Parse_End ();
END_CASE
CASE (LOCATION_TOKEN)
Parse_Vector(New.Location);
END_CASE
CASE (DIRECTION_TOKEN)
Parse_Vector(New.Direction);
END_CASE
CASE (UP_TOKEN)
Parse_Vector(New.Up);
END_CASE
CASE (RIGHT_TOKEN)
Parse_Vector(New.Right);
END_CASE
CASE (SKY_TOKEN)
Parse_Vector(New.Sky);
END_CASE
CASE (LOOK_AT_TOKEN)
Direction_Length = New.Direction.length();
Up_Length = New.Up.length();
Right_Length = New.Right.length();
tempv = cross(New.Up, New.Direction);
Handedness = dot(tempv, New.Right);
Parse_Vector (New.Look_At);
New.Direction = New.Look_At - New.Location;
// Check for zero length direction vector.
if (New.Direction.lengthSqr() < EPSILON)
Error("Camera location and look_at point must be different.");
New.Direction.normalize();
// Save Right vector
tempv = New.Right;
New.Right = cross(New.Sky, New.Direction);
// Avoid DOMAIN error (from Terry Kanakis)
if((fabs(New.Right[X]) < EPSILON) &&
(fabs(New.Right[Y]) < EPSILON) &&
(fabs(New.Right[Z]) < EPSILON))
{
// Restore Right vector
New.Right = tempv;
}
New.Right.normalize();
New.Up = cross(New.Direction, New.Right);
New.Direction *= Direction_Length;
if (Handedness > 0.0)
{
New.Right *= Right_Length;
}
else
{
New.Right *= -Right_Length;
}
New.Up *= Up_Length;
END_CASE
CASE (TRANSLATE_TOKEN)
Parse_Vector (tempv);
New.Translate (tempv);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (tempv);
New.Rotate (tempv);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector (tempv);
New.Scale (tempv);
END_CASE
CASE (TRANSFORM_TOKEN)
New.Transform(Parse_Transform(&Local_Trans));
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix (Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
New.Transform(&Local_Trans);
END_CASE
CASE (BLUR_SAMPLES_TOKEN)
New.Blur_Samples = Parse_Float();
if (New.Blur_Samples <= 0)
Error("Illegal number of focal blur samples.");
END_CASE
CASE (CONFIDENCE_TOKEN)
k1 = Parse_Float();
if ((k1 > 0.0) && (k1 < 1.0))
New.Confidence = k1;
else
Warning("Illegal confidence value. Default is used.");
END_CASE
CASE (VARIANCE_TOKEN)
k1 = Parse_Float();
if ((k1 >= 0.0) && (k1 <= 1.0))
New.Variance = k1;
else
Warning("Illegal variance value. Default is used.");
END_CASE
CASE (APERTURE_TOKEN)
New.Aperture = Parse_Float();
END_CASE
CASE (FOCAL_POINT_TOKEN)
Parse_Vector(tempv);
New.Focal_Point = tempv;
tempv = New.Focal_Point - New.Location;
New.Focal_Distance = tempv.length();
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
}
Parse_End ();
// Make sure the focal distance hasn't been explicitly given
if (New.Focal_Distance < 0.0)
New.Focal_Distance = Direction_Length;
if (New.Focal_Distance == 0.0)
New.Focal_Distance = 1.0;
// Print a warning message if vectors are not perpendicular. [DB 10/94]
k1 = dot(New.Right, New.Up);
k2 = dot(New.Right, New.Direction);
k3 = dot(New.Up, New.Direction);
if ((fabs(k1) > EPSILON) || (fabs(k2) > EPSILON) || (fabs(k3) > EPSILON))
{
Warning("Camera vectors are not perpendicular.\n"
"Making look_at the last statement may help.");
}
}
bool Parser::Parse_Camera_Mods(Camera& New)
{
TRANSFORM Local_Trans;
PIGMENT *Local_Pigment;
MATRIX Local_Matrix;
Vector3d tempv;
DBL k1;
EXPECT_ONE
CASE (TRANSLATE_TOKEN)
Parse_Vector (tempv);
Compute_Translation_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (tempv);
Compute_Rotation_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector(tempv);
Compute_Scaling_Transform(&Local_Trans, tempv);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (TRANSFORM_TOKEN)
Parse_Transform(&Local_Trans);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix(Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
Compose_Transforms(New.Trans, &Local_Trans);
END_CASE
CASE (TNORMAL_TOKEN)
Parse_Begin();
Parse_Tnormal(&(New.Tnormal));
Parse_End();
END_CASE
CASE (LOOK_AT_TOKEN)
Parse_Vector(New.Look_At);
END_CASE
CASE (LOCATION_TOKEN)
Parse_Vector(New.Location);
END_CASE
CASE (DIRECTION_TOKEN)
Parse_Vector(New.Direction);
END_CASE
CASE (UP_TOKEN)
Parse_Vector(New.Up);
END_CASE
CASE (RIGHT_TOKEN)
Parse_Vector(New.Right);
END_CASE
CASE (SKY_TOKEN)
Parse_Vector(New.Sky);
END_CASE
CASE (BLUR_SAMPLES_TOKEN)
New.Blur_Samples_Min = Parse_Float();
if (New.Blur_Samples_Min <= 0)
Error("Illegal number of focal blur samples.");
Parse_Comma();
New.Blur_Samples = (int)Allow_Float(0.0);
if (New.Blur_Samples == 0.0)
{
// oops, user specified no minimum blur samples
New.Blur_Samples = New.Blur_Samples_Min;
New.Blur_Samples_Min = 0;
}
else if (New.Blur_Samples_Min > New.Blur_Samples)
Error("Focal blur samples minimum must not be larger than maximum.");
END_CASE
CASE (CONFIDENCE_TOKEN)
k1 = Parse_Float();
if ((k1 > 0.0) && (k1 < 1.0))
New.Confidence = k1;
else
Warning("Illegal confidence value. Default is used.");
END_CASE
CASE (VARIANCE_TOKEN)
k1 = Parse_Float();
if ((k1 >= 0.0) && (k1 <= 1.0))
New.Variance = k1;
else
Warning("Illegal variance value. Default is used.");
END_CASE
CASE (APERTURE_TOKEN)
New.Aperture = Parse_Float();
END_CASE
CASE (FOCAL_POINT_TOKEN)
Parse_Vector(New.Focal_Point);
END_CASE
CASE (BOKEH_TOKEN)
Parse_Begin();
EXPECT
CASE (PIGMENT_TOKEN)
Local_Pigment = Copy_Pigment(Default_Texture->Pigment);
Parse_Begin();
Parse_Pigment(&Local_Pigment);
Parse_End();
Destroy_Pigment(New.Bokeh);
New.Bokeh = Local_Pigment;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_End();
END_CASE
OTHERWISE
UNGET
return false;
END_CASE
END_EXPECT
return true;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_CSG(int CSG_Type)
{
CSG *Object;
ObjectPtr Local;
int Object_Count = 0;
int Light_Source_Union = true;
Parse_Begin();
if((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
if(CSG_Type & CSG_UNION_TYPE)
Object = new CSGUnion();
else if(CSG_Type & CSG_MERGE_TYPE)
Object = new CSGMerge();
else
Object = new CSGIntersection((CSG_Type & CSG_DIFFERENCE_TYPE) != 0);
while((Local = Parse_Object()) != NULL)
{
if((CSG_Type & CSG_INTERSECTION_TYPE) && (Local->Type & PATCH_OBJECT))
Warning("Patch objects not allowed in intersection.");
Object_Count++;
if((CSG_Type & CSG_DIFFERENCE_TYPE) && (Object_Count > 1))
// warning: Local->Invert will change the pointer if Object is CSG
Local = Local->Invert();
Object->Type |= (Local->Type & CHILDREN_FLAGS);
if(!(Local->Type & LIGHT_SOURCE_OBJECT))
Light_Source_Union = false;
Local->Type |= IS_CHILD_OBJECT;
Link(Local, Object->children);
}
if(Light_Source_Union)
Object->Type |= LT_SRC_UNION_OBJECT;
if(Object_Count < 2)
VersionWarning(150, "Should have at least 2 objects in csg.");
Object->Compute_BBox();
// if the invert flag is in the object mods, the returned pointer will be
// different than the passed one, though the object will still be an instance
// of a CSG. we use dynamic_cast here to aid debugging since the overhead is small.
Object = dynamic_cast(Parse_Object_Mods(reinterpret_cast(Object)));
assert(Object != NULL);
if(CSG_Type & CSG_DIFFERENCE_TYPE)
Object->Type |= CSG_DIFFERENCE_OBJECT;
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Cone ()
{
Cone *Object;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Cone();
Parse_Vector(Object->apex); Parse_Comma ();
Object->apex_radius = Parse_Float(); Parse_Comma ();
Parse_Vector(Object->base); Parse_Comma ();
Object->base_radius = Parse_Float();
EXPECT
CASE(OPEN_TOKEN)
Clear_Flag(Object, CLOSED_FLAG);
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Compute run-time values for the cone */
Object->Compute_Cone_Data();
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Cylinder ()
{
Cone *Object;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Cone();
Object->Cylinder();
Parse_Vector(Object->apex); Parse_Comma();
Parse_Vector(Object->base); Parse_Comma();
Object->apex_radius = Parse_Float();
Object->base_radius = Object->apex_radius;
EXPECT
CASE(OPEN_TOKEN)
Clear_Flag(Object, CLOSED_FLAG);
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Object->Compute_Cylinder_Data();
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Disc ()
{
Disc *Object;
DBL tmpf;
Parse_Begin();
if((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Disc();
Parse_Vector(Object->center); Parse_Comma ();
Parse_Vector(Object->normal); Parse_Comma ();
Object->normal.normalize();
tmpf = Parse_Float(); Parse_Comma ();
Object->oradius2 = tmpf * tmpf;
EXPECT
CASE_FLOAT
tmpf = Parse_Float();
Object->iradius2 = tmpf * tmpf;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Calculate info needed for ray-disc intersections */
tmpf = dot(Object->center, Object->normal);
Object->d = -tmpf;
Object->Compute_Disc();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_HField ()
{
Vector3d Local_Vector;
DBL Temp_Water_Level;
HField *Object;
ImageData *image;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new HField();
image = Parse_Image (HF_FILE);
image->Use = USE_NONE;
Object->bounding_corner1 = Vector3d(0.0, 0.0, 0.0);
Object->bounding_corner2 = Vector3d(image->width - 1.0, 65536.0, image->height - 1.0);
Local_Vector = Vector3d(1.0) / Object->bounding_corner2;
Compute_Scaling_Transform(Object->Trans, Local_Vector);
EXPECT
CASE (WATER_LEVEL_TOKEN)
Temp_Water_Level = Parse_Float();
if (sceneData->EffectiveLanguageVersion() < 200)
Temp_Water_Level /=256.0;
(reinterpret_cast(Object))->bounding_corner1[Y] = 65536.0 * Temp_Water_Level;
END_CASE
CASE (SMOOTH_TOKEN)
Set_Flag(Object, SMOOTHED_FLAG);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_Object_Mods(reinterpret_cast(Object));
Object->Compute_HField(image);
Object->Compute_BBox();
Destroy_Image(image);
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION Parse_Isosurface
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR R. Suzuki
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Isosurface()
{
IsoSurface *Object;
DBL temp;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new IsoSurface();
Object->vm = sceneData->functionVM;
Get_Token();
if(Token.Token_Id != FUNCTION_TOKEN)
Parse_Error(FUNCTION_TOKEN);
Object->Function = Parse_Function();
EXPECT
CASE(CONTAINED_BY_TOKEN)
// TODO - same code as for parametric
Parse_Begin();
{
int Exit_Flag2 = false;
while (!Exit_Flag2)
{
Get_Token();
switch(Token.Token_Id)
{
CASE(BOX_TOKEN)
Object->container = shared_ptr(new ContainedByBox());
Parse_Begin();
Parse_Vector(dynamic_cast(Object->container.get())->corner1);
Parse_Comma();
Parse_Vector(dynamic_cast(Object->container.get())->corner2);
Parse_End();
if (dynamic_cast(Object->container.get())->corner1.x() > dynamic_cast(Object->container.get())->corner2.x())
{
temp = dynamic_cast(Object->container.get())->corner1.x();
dynamic_cast(Object->container.get())->corner1.x() = dynamic_cast(Object->container.get())->corner2.x();
dynamic_cast(Object->container.get())->corner2.x() = temp;
}
if (dynamic_cast(Object->container.get())->corner1.y() > dynamic_cast(Object->container.get())->corner2.y())
{
temp = dynamic_cast(Object->container.get())->corner1.y();
dynamic_cast(Object->container.get())->corner1.y() = dynamic_cast(Object->container.get())->corner2.y();
dynamic_cast(Object->container.get())->corner2.y() = temp;
}
if (dynamic_cast(Object->container.get())->corner1.z() > dynamic_cast(Object->container.get())->corner2.z())
{
temp = dynamic_cast(Object->container.get())->corner1.z();
dynamic_cast(Object->container.get())->corner1.z() = dynamic_cast(Object->container.get())->corner2.z();
dynamic_cast(Object->container.get())->corner2.z() = temp;
}
if (Object->Trans != NULL)
Object->Compute_BBox();
Exit_Flag2 = true;
END_CASE
CASE(SPHERE_TOKEN)
Object->container = shared_ptr(new ContainedBySphere());
Parse_Begin();
Parse_Vector(dynamic_cast(Object->container.get())->center);
Parse_Comma();
dynamic_cast(Object->container.get())->radius = Parse_Float();
Parse_End();
Make_BBox(Object->BBox,
dynamic_cast(Object->container.get())->center.x() - dynamic_cast(Object->container.get())->radius,
dynamic_cast(Object->container.get())->center.y() - dynamic_cast(Object->container.get())->radius,
dynamic_cast(Object->container.get())->center.z() - dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius);
if (Object->Trans != NULL)
Object->Compute_BBox();
Exit_Flag2 = true;
END_CASE
OTHERWISE
UNGET
Exit_Flag2 = true;
END_CASE
}
}
}
Parse_End();
END_CASE
CASE(THRESHOLD_TOKEN)
Object->threshold = Parse_Float();
END_CASE
CASE(ACCURACY_TOKEN)
Object->accuracy = Parse_Float();
END_CASE
CASE(MAX_GRADIENT_TOKEN)
Object->max_gradient = Parse_Float();
END_CASE
CASE(MAX_TRACE_TOKEN)
Object->max_trace = (short)Parse_Float();
END_CASE
CASE(EVALUATE_TOKEN)
Object->eval = true;
Object->eval_param[0] = Parse_Float();
Parse_Comma();
Object->eval_param[1] = Parse_Float();
Parse_Comma();
Object->eval_param[2] = Parse_Float();
END_CASE
CASE(OPEN_TOKEN)
Object->closed = false;
END_CASE
CASE(ALL_INTERSECTIONS_TOKEN)
Object->max_trace = ISOSURFACE_MAXTRACE;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if (Object->accuracy <= 0.0)
{
Warning("Isosurface 'accuracy' is not positive. Using 0.001 (default).");
Object->accuracy = 0.001;
}
if (Object->max_gradient <= 0.0)
{
Warning("Isosurface 'max_gradient' is not positive. Using 1.1 (default).");
Object->max_gradient = 1.1;
}
if (Object->max_trace > ISOSURFACE_MAXTRACE)
{
Warning("Isosurface 'max_trace' exceeds maximum of %d. Using maximum.", (int)ISOSURFACE_MAXTRACE);
Object->max_trace = ISOSURFACE_MAXTRACE;
}
if (Object->max_trace < 1)
{
Warning("Isosurface 'max_trace' is not positive. Using 1 (default).");
Object->max_trace = 1;
}
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Julia_Fractal
*
* INPUT None
*
* OUTPUT Fractal Objecstructure filledt
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Pascal Massimino
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Dec 1994 : Adopted to version 3.0. [DB]
* Sept 1995 : Total rewrite for new syntax [TW]
*
******************************************************************************/
ObjectPtr Parser::Parse_Julia_Fractal ()
{
Fractal *Object;
DBL P;
Parse_Begin();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return(reinterpret_cast(Object));
Object = new Fractal();
Parse_Vector4D(Object->Julia_Parm);
EXPECT
CASE(MAX_ITERATION_TOKEN)
Object->Num_Iterations = (int)floor(Parse_Float());
if (Object->Num_Iterations <= 0)
{
Object->Num_Iterations = 1;
}
END_CASE
CASE(SLICE_TOKEN)
Parse_Vector4D(Object->Slice);
Parse_Comma();
Object->SliceDist = Parse_Float();
/* normalize slice vector */
V4D_Dot(P,Object->Slice, Object->Slice);
if (fabs(P) < EPSILON)
{
Error("Slice vector is zero.");
}
if (fabs(Object->Slice[T]) < EPSILON)
{
Error("Slice t component is zero.");
}
P = sqrt(P);
V4D_InverseScaleEq(Object->Slice, P);
END_CASE
CASE(PRECISION_TOKEN)
P = Parse_Float();
if ( P < 1.0 )
{
P = 1.0;
}
Object->Precision = 1.0 / P;
END_CASE
CASE(FLOAT_FUNCT_TOKEN)
switch(Token.Function_Id)
{
case EXP_TOKEN:
Object->Sub_Type = EXP_STYPE;
break;
case LN_TOKEN:
Object->Sub_Type = LN_STYPE;
break;
case SIN_TOKEN:
Object->Sub_Type = SIN_STYPE;
break;
case ASIN_TOKEN:
Object->Sub_Type = ASIN_STYPE;
break;
case COS_TOKEN:
Object->Sub_Type = COS_STYPE;
break;
case ACOS_TOKEN:
Object->Sub_Type = ACOS_STYPE;
break;
case TAN_TOKEN:
Object->Sub_Type = TAN_STYPE;
break;
case ATAN_TOKEN:
Object->Sub_Type = ATAN_STYPE;
break;
case COSH_TOKEN:
Object->Sub_Type = COSH_STYPE;
break;
case SINH_TOKEN:
Object->Sub_Type = SINH_STYPE;
break;
case TANH_TOKEN:
Object->Sub_Type = TANH_STYPE;
break;
case ATANH_TOKEN:
Object->Sub_Type = ATANH_STYPE;
break;
case ACOSH_TOKEN:
Object->Sub_Type = ACOSH_STYPE;
break;
case ASINH_TOKEN:
Object->Sub_Type = ASINH_STYPE;
break;
default: Expectation_Error ("fractal keyword");
}
END_CASE
/* if any of the next become supported by the expression parser,
* then their handling would need to move above to the FLOAT_FUNCT_TOKEN
* case above.
*/
CASE(SQR_TOKEN)
Object->Sub_Type = SQR_STYPE;
END_CASE
CASE(PWR_TOKEN)
Object->Sub_Type = PWR_STYPE;
Parse_Float_Param2(&Object->exponent.x,&Object->exponent.y);
END_CASE
CASE(CUBE_TOKEN)
Object->Sub_Type = CUBE_STYPE;
END_CASE
CASE(RECIPROCAL_TOKEN)
Object->Sub_Type = RECIPROCAL_STYPE;
END_CASE
CASE(HYPERCOMPLEX_TOKEN)
Object->Algebra = HYPERCOMPLEX_TYPE;
END_CASE
CASE(QUATERNION_TOKEN)
Object->Algebra = QUATERNION_TYPE;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_Object_Mods(reinterpret_cast(Object));
int num_iterations = Object->SetUp_Fractal();
if (num_iterations > sceneData->Fractal_Iteration_Stack_Length)
{
sceneData->Fractal_Iteration_Stack_Length = num_iterations;
SceneThreadData *td = GetParserDataPtr();
Fractal::Allocate_Iteration_Stack(td->Fractal_IStack, sceneData->Fractal_Iteration_Stack_Length);
}
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Lathe
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Read a lathe primitive.
*
* CHANGES
*
* Jun 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Lathe()
{
int i;
Lathe *Object;
Vector2d *Points;
Parse_Begin();
if((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return(reinterpret_cast(Object));
Object = new Lathe();
/* Determine kind of spline used and aspect ratio. */
EXPECT
CASE(LINEAR_SPLINE_TOKEN)
Object->Spline_Type = LINEAR_SPLINE;
END_CASE
CASE(QUADRATIC_SPLINE_TOKEN)
Object->Spline_Type = QUADRATIC_SPLINE;
END_CASE
CASE(CUBIC_SPLINE_TOKEN)
Object->Spline_Type = CUBIC_SPLINE;
END_CASE
CASE(BEZIER_SPLINE_TOKEN)
Object->Spline_Type = BEZIER_SPLINE;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Get number of points. */
Object->Number = (int)Parse_Float();
switch (Object->Spline_Type)
{
case LINEAR_SPLINE :
if (Object->Number < 2)
{
Error("Lathe with linear splines must have at least two points.");
}
break;
case QUADRATIC_SPLINE :
if (Object->Number < 3)
{
Error("Lathe with quadratic splines must have at least three points.");
}
break;
case CUBIC_SPLINE :
if (Object->Number < 4)
{
Error("Prism with cubic splines must have at least four points.");
}
break;
case BEZIER_SPLINE :
if ((Object->Number & 3) != 0)
{
Error("Lathe with Bezier splines must have four points per segment.");
}
break;
}
/* Get temporary points describing the rotated curve. */
Points = reinterpret_cast(POV_MALLOC(Object->Number*sizeof(Vector2d), "temporary lathe points"));
/* Read points (x : radius; y : height; z : not used). */
for (i = 0; i < Object->Number; i++)
{
Parse_Comma();
Parse_UV_Vect(Points[i]);
if ((i > 0) && (i < Object->Number - 1) && (Points[i][X] < 0.0))
{
Error("Incorrect point in lathe.");
}
}
/* Compute spline segments. */
Object->Compute_Lathe(Points, GetParserDataPtr());
/* Compute bounding box. */
Object->Compute_BBox();
/* Parse object's modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
/* Destroy temporary points. */
POV_FREE(Points);
if (Object->Spline->BCyl->number > sceneData->Max_Bounding_Cylinders)
{
SceneThreadData *td = GetParserDataPtr();
sceneData->Max_Bounding_Cylinders = Object->Spline->BCyl->number;
td->BCyl_Intervals.reserve(4*sceneData->Max_Bounding_Cylinders);
td->BCyl_RInt.reserve(2*sceneData->Max_Bounding_Cylinders);
td->BCyl_HInt.reserve(2*sceneData->Max_Bounding_Cylinders);
}
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Light_Group
*
* INPUT
*
* -
*
* OUTPUT
*
* RETURNS
*
* Light group object
*
* AUTHOR
*
* Thorsten Froehlich [trf]
*
* DESCRIPTION
*
* Parse light_group object
*
* CHANGES
*
* Jun 2000 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Light_Group()
{
CSG *Object;
ObjectPtr Local;
Vector3d Local_Vector;
MATRIX Local_Matrix;
TRANSFORM Local_Trans;
Parse_Begin();
Object = new CSGUnion();
Object->Type |= LIGHT_GROUP_OBJECT;
Set_Flag(Object, NO_GLOBAL_LIGHTS_FLAG);
while((Local = Parse_Object()) != NULL)
{
// prevent light sources from being added to Frame.Light_Sources
if((Local->Type & LIGHT_SOURCE_OBJECT) == LIGHT_SOURCE_OBJECT)
Local->Type |= LIGHT_GROUP_LIGHT_OBJECT;
Local->Type |= IS_CHILD_OBJECT;
Link(Local, Object->children);
}
Promote_Local_Lights(Object); // in lightgrp.cpp [trf]
Object->Compute_BBox();
// Note: We cannot use Parse_Object_Mods here because
// it would allow all kinds of modifiers. However,
// changing it to not allow those would slow it down,
// so the bits of code needed are just duplicated
// here. [trf]
// Parse_Object_Mods(reinterpret_cast(Object));
EXPECT
CASE (TRANSLATE_TOKEN)
Parse_Vector (Local_Vector);
Compute_Translation_Transform(&Local_Trans, Local_Vector);
Translate_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (Local_Vector);
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
Rotate_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector (Local_Vector);
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
Scale_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (TRANSFORM_TOKEN)
Transform_Object (reinterpret_cast(Object), Parse_Transform(&Local_Trans));
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix (Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
Transform_Object (reinterpret_cast(Object), &Local_Trans);
END_CASE
CASE (GLOBAL_LIGHTS_TOKEN)
Bool_Flag (Object, NO_GLOBAL_LIGHTS_FLAG, !(Allow_Float(1.0) > 0.5));
END_CASE
CASE(PHOTONS_TOKEN)
Parse_Begin();
EXPECT
CASE(TARGET_TOKEN)
Object->Ph_Density = Allow_Float(1.0);
if (Object->Ph_Density > 0)
{
Set_Flag(Object,PH_TARGET_FLAG);
CheckPassThru(reinterpret_cast(Object), PH_TARGET_FLAG);
}
else
{
Clear_Flag(Object, PH_TARGET_FLAG);
}
END_CASE
CASE(REFRACTION_TOKEN)
if((int)Parse_Float())
{
Set_Flag(Object, PH_RFR_ON_FLAG);
Clear_Flag(Object, PH_RFR_OFF_FLAG);
CheckPassThru(reinterpret_cast(Object), PH_RFR_ON_FLAG);
}
else
{
Clear_Flag(Object, PH_RFR_ON_FLAG);
Set_Flag(Object, PH_RFR_OFF_FLAG);
}
END_CASE
CASE(REFLECTION_TOKEN)
if((int)Parse_Float())
{
Set_Flag(Object, PH_RFL_ON_FLAG);
Clear_Flag(Object, PH_RFL_OFF_FLAG);
}
else
{
Clear_Flag(Object, PH_RFL_ON_FLAG);
Set_Flag(Object, PH_RFL_OFF_FLAG);
}
END_CASE
CASE(PASS_THROUGH_TOKEN)
if((int)Allow_Float(1.0))
{
Set_Flag(Object, PH_PASSTHRU_FLAG);
CheckPassThru(reinterpret_cast(Object), PH_PASSTHRU_FLAG);
}
else
{
Clear_Flag(Object, PH_PASSTHRU_FLAG);
}
END_CASE
CASE(COLLECT_TOKEN)
Bool_Flag (Object, PH_IGNORE_PHOTONS_FLAG, !(Allow_Float(1.0) > 0.0));
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_End();
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Set_CSG_Children_Flag(Object, Test_Flag(Object, NO_GLOBAL_LIGHTS_FLAG),
NO_GLOBAL_LIGHTS_FLAG, NO_GLOBAL_LIGHTS_SET_FLAG);
Parse_End();
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Light_Source ()
{
DBL Len;
Vector3d Local_Vector;
MATRIX Local_Matrix;
TRANSFORM Local_Trans;
LightSource *Object;
/* NK ---- */
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new LightSource ();
Parse_Vector(Object->Center);
Parse_Comma();
Parse_Colour(Object->colour);
EXPECT
/* NK phmap */
CASE (COLOUR_MAP_TOKEN)
// TODO - apparently this undocumented syntax was once intended to do something related to dispersion,
// but in 3.7 is dysfunctional, doing nothing except provide an undocumented means of averaging
// different colours. Can we safely drop it?
Warning("Undocumented syntax ignored (colour_map in light_source);"
" future versions of POV-Ray may drop support for it entirely.");
(void)Parse_Colour_Map ();
END_CASE
CASE(PHOTONS_TOKEN)
Parse_Begin();
EXPECT
#ifdef GLOBAL_PHOTONS
CASE(GLOBAL_TOKEN)
Object->Ph_Density = Allow_Float(1.0);
if (Object->Ph_Density > 0)
{
Set_Flag(Object, PH_TARGET_FLAG);
/*CheckPassThru(Object, PH_TARGET_FLAG);*/
}
else
{
Clear_Flag(Object, PH_TARGET_FLAG);
}
END_CASE
#endif
CASE(REFRACTION_TOKEN)
if((int)Parse_Float())
{
Set_Flag(Object, PH_RFR_ON_FLAG);
Clear_Flag(Object, PH_RFR_OFF_FLAG);
}
else
{
Clear_Flag(Object, PH_RFR_ON_FLAG);
Set_Flag(Object, PH_RFR_OFF_FLAG);
}
END_CASE
CASE(REFLECTION_TOKEN)
if((int)Parse_Float())
{
Set_Flag(Object, PH_RFL_ON_FLAG);
Clear_Flag(Object, PH_RFL_OFF_FLAG);
}
else
{
Clear_Flag(Object, PH_RFL_ON_FLAG);
Set_Flag(Object, PH_RFL_OFF_FLAG);
}
END_CASE
CASE (AREA_LIGHT_TOKEN)
Object->Photon_Area_Light = true;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_End();
END_CASE
CASE (LOOKS_LIKE_TOKEN)
if (!Object->children.empty())
Error("Only one looks_like allowed per light_source.");
Parse_Begin ();
Object->Type &= ~(int)PATCH_OBJECT;
Object->children.push_back(Parse_Object());
if(Object->children.empty() || (Object->children[0] == NULL))
Expectation_Error("object");
Compute_Translation_Transform(&Local_Trans, Object->Center);
Translate_Object(Object->children[0], Object->Center, &Local_Trans);
Object->children[0] = Parse_Object_Mods (Object->children[0]);
Set_Flag(Object->children[0], NO_SHADOW_FLAG);
Set_Flag(Object, NO_SHADOW_FLAG);
Object->Type |= (Object->children[0]->Type & CHILDREN_FLAGS);
Set_Flag(Object, PH_PASSTHRU_FLAG);
END_CASE
CASE (PROJECTED_THROUGH_TOKEN)
if (Object->Projected_Through_Object != NULL)
Error("Only one projected through allowed per light_source.");
Parse_Begin ();
Object->Type &= ~(int)PATCH_OBJECT;
if ((Object->Projected_Through_Object = Parse_Object ()) == NULL)
Expectation_Error ("object");
Object->Projected_Through_Object = Parse_Object_Mods (Object->Projected_Through_Object);
Set_Flag(Object, NO_SHADOW_FLAG);
Set_Flag(Object, PH_PASSTHRU_FLAG);
END_CASE
CASE (FILL_LIGHT_TOKEN)
Object->Light_Type = FILL_LIGHT_SOURCE;
END_CASE
CASE (PARALLEL_TOKEN)
Object->Parallel= true;
END_CASE
CASE (SPOTLIGHT_TOKEN)
Object->Light_Type = SPOT_SOURCE;
Object->Radius = cos(30 * M_PI_180);
Object->Falloff = cos(45 * M_PI_180);
Object->Coeff = 0;
END_CASE
CASE (CYLINDER_TOKEN)
Object->Light_Type = CYLINDER_SOURCE;
Object->Radius = 0.75;
Object->Falloff = 1;
Object->Coeff = 0;
Object->Parallel = true;
END_CASE
CASE (POINT_AT_TOKEN)
if ((Object->Light_Type == SPOT_SOURCE) || (Object->Light_Type == CYLINDER_SOURCE) ||
Object->Parallel)
{
Parse_Vector(Object->Points_At);
}
else
{
Not_With ("point_at","standard light source");
}
END_CASE
CASE (TIGHTNESS_TOKEN)
if ((Object->Light_Type == SPOT_SOURCE) || (Object->Light_Type == CYLINDER_SOURCE))
Object->Coeff = Parse_Float();
else
Not_With ("tightness","standard light source");
END_CASE
CASE (RADIUS_TOKEN)
if ((Object->Light_Type == SPOT_SOURCE) || (Object->Light_Type == CYLINDER_SOURCE))
{
Object->Radius = Parse_Float();
if (Object->Light_Type == SPOT_SOURCE)
{
Object->Radius = cos(Object->Radius * M_PI_180);
}
}
else
Not_With ("radius","standard light source");
END_CASE
CASE (FALLOFF_TOKEN)
if ((Object->Light_Type == SPOT_SOURCE) || (Object->Light_Type == CYLINDER_SOURCE))
{
Object->Falloff = Parse_Float();
if (Object->Light_Type == SPOT_SOURCE)
{
Object->Falloff = cos(Object->Falloff * M_PI_180);
}
}
else
Not_With ("falloff","standard light source");
END_CASE
CASE (FADE_DISTANCE_TOKEN)
Object->Fade_Distance = Parse_Float();
END_CASE
CASE (FADE_POWER_TOKEN)
Object->Fade_Power = Parse_Float();
END_CASE
CASE (AREA_LIGHT_TOKEN)
Object->Area_Light = true;
Parse_Vector (Object->Axis1); Parse_Comma ();
Parse_Vector (Object->Axis2); Parse_Comma ();
Object->Area_Size1 = (int)Parse_Float();
if (Object->Area_Size1 == 0)
Error("Area size must be greater than zero.");
Parse_Comma ();
Object->Area_Size2 = (int)Parse_Float();
if (Object->Area_Size2 == 0)
Error("Area size must be greater than zero.");
END_CASE
CASE (JITTER_TOKEN)
Object->Jitter = true;
END_CASE
/* Orient area lights to the point [ENB 9/97] */
CASE (ORIENT_TOKEN)
Object->Orient = true;
if (!(Object->Area_Light))
{
Warning("Orient only affects area_light");
}
END_CASE
/* Circular area lights [ENB 9/97] */
CASE (CIRCULAR_TOKEN)
Object->Circular = true;
if (!(Object->Area_Light))
{
Warning("Circular only affects area_light");
}
END_CASE
// JN2007: Full area lighting:
CASE (AREA_ILLUMINATION_TOKEN)
Object->Use_Full_Area_Lighting = Allow_Float(1.0) > 0.0;
if (!(Object->Area_Light))
{
Warning("Area_illumination only affects area_light");
}
END_CASE
CASE (ADAPTIVE_TOKEN)
Object->Adaptive_Level = (int)Parse_Float();
END_CASE
CASE (MEDIA_ATTENUATION_TOKEN)
Object->Media_Attenuation = Allow_Float(1.0) > 0.0;
END_CASE
CASE (MEDIA_INTERACTION_TOKEN)
Object->Media_Interaction = Allow_Float(1.0) > 0.0;
END_CASE
CASE (TRANSLATE_TOKEN)
Parse_Vector (Local_Vector);
Compute_Translation_Transform(&Local_Trans, Local_Vector);
Translate_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (ROTATE_TOKEN)
Parse_Vector (Local_Vector);
Compute_Rotation_Transform(&Local_Trans, Local_Vector);
Rotate_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (SCALE_TOKEN)
Parse_Scale_Vector (Local_Vector);
Compute_Scaling_Transform(&Local_Trans, Local_Vector);
Scale_Object (reinterpret_cast(Object), Local_Vector, &Local_Trans);
END_CASE
CASE (TRANSFORM_TOKEN)
Transform_Object (reinterpret_cast(Object), Parse_Transform(&Local_Trans));
END_CASE
CASE (MATRIX_TOKEN)
Parse_Matrix (Local_Matrix);
Compute_Matrix_Transform(&Local_Trans, Local_Matrix);
Transform_Object (reinterpret_cast(Object), &Local_Trans);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if ((Object->Fade_Power != 0) && (fabs(Object->Fade_Distance) < EPSILON) && (sceneData->EffectiveLanguageVersion() < 371))
{
Warning("fade_power with fade_distance 0 is not supported in legacy (pre-3.71) scenes; fade_power is ignored.");
Object->Fade_Power = 0;
Object->Fade_Distance = 0;
}
Parse_End ();
Object->Direction = Object->Points_At - Object->Center;
Len = Object->Direction.length();
if (Len > EPSILON)
{
Object->Direction /= Len;
}
/* Make sure that circular light sources are larger than 1 by x [ENB 9/97] */
if (Object->Circular)
{
if ((Object->Area_Size1 <= 1) || (Object->Area_Size2 <= 1))
{
Error("Circular area light must have more than 1 point per axis");
}
}
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Mesh
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* OBJECT
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Read a triangle mesh.
*
* CHANGES
*
* Feb 1995 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Mesh()
{
/* NK 1998 - added all sorts of uv variables*/
int i;
int number_of_normals, number_of_textures, number_of_triangles, number_of_vertices, number_of_uvcoords;
int max_normals, max_textures, max_triangles, max_vertices, max_uvcoords;
DBL l1, l2, l3;
Vector3d D1, D2, P1, P2, P3, N1, N2, N3, N;
Vector2d UV1, UV2, UV3;
MeshVector *Normals, *Vertices;
TEXTURE **Textures;
MeshUVVector *UVCoords;
Mesh *Object;
MESH_TRIANGLE *Triangles;
bool fully_textured=true;
/* NK 1998 */
Vector3d Inside_Vect;
TEXTURE *t2, *t3;
bool foundZeroNormal=false;
Inside_Vect = Vector3d(0.0, 0.0, 0.0);
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
/* Create object. */
Object = new Mesh();
/* Allocate temporary normals, textures, triangles and vertices. */
max_normals = 256;
max_vertices = 256;
max_textures = 16;
max_triangles = 256;
Normals = reinterpret_cast(POV_MALLOC(max_normals*sizeof(MeshVector), "temporary triangle mesh data"));
Textures = reinterpret_cast(POV_MALLOC(max_textures*sizeof(TEXTURE *), "temporary triangle mesh data"));
Triangles = reinterpret_cast(POV_MALLOC(max_triangles*sizeof(MESH_TRIANGLE), "temporary triangle mesh data"));
Vertices = reinterpret_cast(POV_MALLOC(max_vertices*sizeof(MeshVector), "temporary triangle mesh data"));
/* Read raw triangle file. */
number_of_normals = 0;
number_of_textures = 0;
number_of_triangles = 0;
number_of_vertices = 0;
max_uvcoords = 256;
UVCoords = reinterpret_cast(POV_MALLOC(max_uvcoords*sizeof(MeshUVVector), "temporary triangle mesh data"));
number_of_uvcoords = 0;
/* Create hash tables. */
Object->Create_Mesh_Hash_Tables();
EXPECT
CASE(TRIANGLE_TOKEN)
Parse_Begin();
Parse_Vector(P1); Parse_Comma();
Parse_Vector(P2); Parse_Comma();
Parse_Vector(P3);
if (!Object->Degenerate(P1, P2, P3))
{
if (number_of_triangles >= max_triangles)
{
if (max_triangles >= INT_MAX/2)
{
Error("Too many triangles in triangle mesh.");
}
max_triangles *= 2;
Triangles = reinterpret_cast(POV_REALLOC(Triangles, max_triangles*sizeof(MESH_TRIANGLE), "triangle triangle mesh data"));
}
/* Init triangle. */
Object->Init_Mesh_Triangle(&Triangles[number_of_triangles]);
Triangles[number_of_triangles].P1 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P1);
Triangles[number_of_triangles].P2 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P2);
Triangles[number_of_triangles].P3 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P3);
/* NK 1998 */
Parse_Three_UVCoords(UV1,UV2,UV3);
Triangles[number_of_triangles].UV1 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV1);
Triangles[number_of_triangles].UV2 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV2);
Triangles[number_of_triangles].UV3 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV3);
/* NK ---- */
/* NK */
/* read possibly three instead of only one texture */
/* read these before compute!!! */
t2 = t3 = NULL;
Triangles[number_of_triangles].Texture = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, Parse_Mesh_Texture(&t2,&t3));
if (t2) Triangles[number_of_triangles].Texture2 = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, t2);
if (t3) Triangles[number_of_triangles].Texture3 = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, t3);
if (t2 || t3) Triangles[number_of_triangles].ThreeTex = true;
Object->Compute_Mesh_Triangle(&Triangles[number_of_triangles], false, P1, P2, P3, N);
Triangles[number_of_triangles].Normal_Ind = Object->Mesh_Hash_Normal(&number_of_normals, &max_normals, &Normals, N);
if(Triangles[number_of_triangles].Texture < 0)
fully_textured = false;
number_of_triangles++;
}
/* NK degenerate fix */
else
{
/* parse the uv and texture info - even though we'll just throw it
away. why? if not we get a parse error - we should just ignore the
degenerate triangle */
t2=t3=NULL;
Parse_Three_UVCoords(UV1,UV2,UV3);
Parse_Mesh_Texture(&t2,&t3);
}
Parse_End();
END_CASE
CASE(SMOOTH_TRIANGLE_TOKEN)
Parse_Begin();
Parse_Vector(P1); Parse_Comma();
Parse_Vector(N1); Parse_Comma();
if(fabs(N1[X]).");
foundZeroNormal = true;
}
Parse_Vector(P2); Parse_Comma();
Parse_Vector(N2); Parse_Comma();
if(fabs(N2[X]).");
foundZeroNormal = true;
}
Parse_Vector(P3); Parse_Comma();
Parse_Vector(N3);
if(fabs(N3[X]).");
foundZeroNormal = true;
}
l1 = N1.length();
l2 = N2.length();
l3 = N3.length();
if ((l1 != 0.0) && (l2 != 0.0) && (l3 != 0.0) && (!Object->Degenerate(P1, P2, P3)))
{
if (number_of_triangles >= max_triangles)
{
if (max_triangles >= INT_MAX/2)
Error("Too many triangles in triangle mesh.");
max_triangles *= 2;
Triangles = reinterpret_cast(POV_REALLOC(Triangles, max_triangles*sizeof(MESH_TRIANGLE), "triangle triangle mesh data"));
}
N1 /= l1;
N2 /= l2;
N3 /= l3;
/* Init triangle. */
Object->Init_Mesh_Triangle(&Triangles[number_of_triangles]);
Triangles[number_of_triangles].P1 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P1);
Triangles[number_of_triangles].P2 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P2);
Triangles[number_of_triangles].P3 = Object->Mesh_Hash_Vertex(&number_of_vertices, &max_vertices, &Vertices, P3);
/* Check for equal normals. */
D1 = N1 - N2;
D2 = N1 - N3;
l1 = D1.lengthSqr();
l2 = D2.lengthSqr();
/* NK 1998 */
Parse_Three_UVCoords(UV1,UV2,UV3);
Triangles[number_of_triangles].UV1 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV1);
Triangles[number_of_triangles].UV2 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV2);
Triangles[number_of_triangles].UV3 = Object->Mesh_Hash_UV(&number_of_uvcoords, &max_uvcoords, &UVCoords, UV3);
/* read possibly three instead of only one texture */
/* read these before compute!!! */
t2 = t3 = NULL;
Triangles[number_of_triangles].Texture = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, Parse_Mesh_Texture(&t2,&t3));
if (t2) Triangles[number_of_triangles].Texture2 = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, t2);
if (t3) Triangles[number_of_triangles].Texture3 = Object->Mesh_Hash_Texture(&number_of_textures, &max_textures, &Textures, t3);
if (t2 || t3) Triangles[number_of_triangles].ThreeTex = true;
if ((fabs(l1) > EPSILON) || (fabs(l2) > EPSILON))
{
/* Smooth triangle. */
Triangles[number_of_triangles].N1 = Object->Mesh_Hash_Normal(&number_of_normals, &max_normals, &Normals, N1);
Triangles[number_of_triangles].N2 = Object->Mesh_Hash_Normal(&number_of_normals, &max_normals, &Normals, N2);
Triangles[number_of_triangles].N3 = Object->Mesh_Hash_Normal(&number_of_normals, &max_normals, &Normals, N3);
Object->Compute_Mesh_Triangle(&Triangles[number_of_triangles], true, P1, P2, P3, N);
}
else
{
/* Flat triangle. */
Object->Compute_Mesh_Triangle(&Triangles[number_of_triangles], false, P1, P2, P3, N);
}
Triangles[number_of_triangles].Normal_Ind = Object->Mesh_Hash_Normal(&number_of_normals, &max_normals, &Normals, N);
if (Triangles[number_of_triangles].Texture < 0)
{
fully_textured = false;
}
number_of_triangles++;
}
/* NK degenerate fix */
else
{
/* parse the uv and texture info - even though we'll just throw it
away. why? if not we get a parse error - we should just ignore the
degenerate triangle */
t2=t3=NULL;
Parse_Three_UVCoords(UV1,UV2,UV3);
Parse_Mesh_Texture(&t2,&t3);
}
Parse_End();
END_CASE
/* NK 1998 */
CASE(INSIDE_VECTOR_TOKEN)
Parse_Vector(Inside_Vect);
END_CASE
/* NK ---- */
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Destroy hash tables. */
Object->Destroy_Mesh_Hash_Tables();
/* If there are no triangles something went wrong. */
if (number_of_triangles == 0)
{
Error("No triangles in triangle mesh.");
}
/* Init triangle mesh data. */
Object->Data = reinterpret_cast(POV_MALLOC(sizeof(MESH_DATA), "triangle mesh data"));
Object->Data->References = 1;
Object->Data->Tree = NULL;
/* NK 1998 */
if( (fabs(Inside_Vect[X]) < EPSILON) && (fabs(Inside_Vect[Y]) < EPSILON) && (fabs(Inside_Vect[Z]) < EPSILON))
{
Object->has_inside_vector=false;
Object->Type |= PATCH_OBJECT;
}
else
{
Object->Data->Inside_Vect = Inside_Vect.normalized();
Object->has_inside_vector=true;
Object->Type &= ~PATCH_OBJECT;
}
Object->Data->Normals = NULL;
/* [LSK] Removed "Data->" */
Object->Textures = NULL;
Object->Data->Triangles = NULL;
Object->Data->Vertices = NULL;
/* Allocate memory for normals, textures, triangles and vertices. */
Object->Number_Of_Textures = number_of_textures;
Object->Data->Number_Of_Normals = number_of_normals;
Object->Data->Number_Of_Triangles = number_of_triangles;
Object->Data->Number_Of_Vertices = number_of_vertices;
Object->Data->Normals = reinterpret_cast(POV_MALLOC(number_of_normals*sizeof(MeshVector), "triangle mesh data"));
if (number_of_textures)
{
Set_Flag(Object, MULTITEXTURE_FLAG);
/* [LSK] Removed "Data->" */
Object->Textures = reinterpret_cast(POV_MALLOC(number_of_textures*sizeof(TEXTURE *), "triangle mesh data"));
}
Object->Data->Triangles = reinterpret_cast(POV_MALLOC(number_of_triangles*sizeof(MESH_TRIANGLE), "triangle mesh data"));
Object->Data->Vertices = reinterpret_cast(POV_MALLOC(number_of_vertices*sizeof(MeshVector), "triangle mesh data"));
/* Copy normals, textures, triangles and vertices into mesh. */
for (i = 0; i < number_of_normals; i++)
{
Object->Data->Normals[i] = Normals[i];
}
for (i = 0; i < number_of_textures; i++)
{
/* [LSK] Removed "Data->" */
Object->Textures[i] = Copy_Textures(Textures[i]);
Post_Textures(Object->Textures[i]);
/* now free the texture, in order to decrement the reference count */
Destroy_Textures(Textures[i]);
}
if (fully_textured)
{
Object->Type |= TEXTURED_OBJECT;
}
for (i = 0; i < number_of_triangles; i++)
{
Object->Data->Triangles[i] = Triangles[i];
}
for (i = 0; i < number_of_vertices; i++)
{
Object->Data->Vertices[i] = Vertices[i];
}
/* NK 1998 */
/* do the four steps above, but for UV coordinates*/
Object->Data->UVCoords = NULL;
Object->Data->Number_Of_UVCoords = number_of_uvcoords;
Object->Data->UVCoords = reinterpret_cast(POV_MALLOC(number_of_uvcoords*sizeof(MeshUVVector), "triangle mesh data"));
for (i = 0; i < number_of_uvcoords; i++)
{
Object->Data->UVCoords[i] = UVCoords[i];
}
POV_FREE(UVCoords);
/* NK ---- */
/* Free temporary memory. */
POV_FREE(Normals);
POV_FREE(Textures);
POV_FREE(Triangles);
POV_FREE(Vertices);
/*
Render_Info("Mesh: %ld bytes: %ld vertices, %ld normals, %ld textures, %ld triangles, %ld uv-coords\n",
Object->Data->Number_Of_Normals*sizeof(MeshVector)+
Object->Number_Of_Textures*sizeof(TEXTURE *)+
Object->Data->Number_Of_Triangles*sizeof(MESH_TRIANGLE)+
Object->Data->Number_Of_Vertices*sizeof(MeshVector)+
Object->Data->Number_Of_UVCoords*sizeof(MeshUVVector),
Object->Data->Number_Of_Vertices,
Object->Data->Number_Of_Normals,
Object->Number_Of_Textures,
Object->Data->Number_Of_Triangles,
Object->Data->Number_Of_UVCoords);
*/
/* Create bounding box. */
Object->Compute_BBox();
/* Parse object modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
/* Create bounding box tree. */
Object->Build_Mesh_BBox_Tree();
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Mesh2
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* OBJECT
*
* AUTHOR
*
* Nathan Kopp
*
* DESCRIPTION
*
* Read a triangle mesh - syntax version 2.
*
* CHANGES
*
* Feb 1998 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Mesh2()
{
int i;
int number_of_normals, number_of_textures, number_of_triangles, number_of_vertices, number_of_uvcoords;
int number_of_normal_indices;
int a,b,c;
int n1, n2, n3;
bool found_normal_indices = false;
bool found_uv_indices = false;
bool fully_textured = true;
bool foundZeroNormal = false;
DBL l1, l2;
Vector3d D1, D2, P1, P2, P3, N1, N;
Vector3d Inside_Vect;
Vector2d UV1;
MeshVector *Normals = NULL;
MeshVector *Vertices = NULL;
TEXTURE **Textures = NULL;
MeshUVVector *UVCoords = NULL;
Mesh *Object;
MESH_TRIANGLE *Triangles;
Inside_Vect = Vector3d(0.0, 0.0, 0.0);
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return(reinterpret_cast(Object));
/* Create object. */
Object = new Mesh();
/* normals, uvcoords, and textures are optional */
number_of_vertices = 0;
number_of_uvcoords = 0;
number_of_textures = 0;
number_of_normals = 0;
number_of_normal_indices = 0;
/* ----------------- Get the Normals & UV Vectors & Textures ------------ */
EXPECT
/* ------------------- Get the Vertices ------------------- */
CASE(VERTEX_VECTORS_TOKEN)
if (number_of_vertices>0)
{
Warning("Duplicate vertex_vectors block; ignoring previous block.");
POV_FREE(Vertices);
}
Parse_Begin();
number_of_vertices = (int)Parse_Float(); Parse_Comma();
if (number_of_vertices<=0)
Error("No vertices in triangle mesh.");
/* allocate memory for vertices */
Vertices = reinterpret_cast(POV_MALLOC(number_of_vertices*sizeof(MeshVector), "triangle mesh data"));
for(i=0; i0)
{
Warning("Duplicate normal_vectors block; ignoring previous block.");
POV_FREE(Normals);
}
Parse_Begin();
number_of_normals = (int)Parse_Float(); Parse_Comma();
if (number_of_normals>0)
{
Normals = reinterpret_cast(POV_MALLOC(number_of_normals*sizeof(MeshVector), "triangle mesh data"));
/* leave space in the array for the raw triangle normals */
for(i=0; i.");
foundZeroNormal = true;
}
N1.normalize();
Normals[i] = MeshVector(N1);
}
}
Parse_End();
END_CASE
CASE(UV_VECTORS_TOKEN)
if (number_of_uvcoords>0)
{
Warning("Duplicate uv_vectors block; ignoring previous block.");
POV_FREE(UVCoords);
}
Parse_Begin();
number_of_uvcoords = (int)Parse_Float(); Parse_Comma();
if (number_of_uvcoords>0)
{
UVCoords = reinterpret_cast(POV_MALLOC(number_of_uvcoords*sizeof(MeshUVVector), "triangle mesh data"));
for(i=0; i0)
{
Textures = reinterpret_cast(POV_MALLOC(number_of_textures*sizeof(TEXTURE *), "triangle mesh data"));
for(i=0; i(Token.Data));
*/
GET(TEXTURE_TOKEN);
Parse_Begin();
Textures[i] = Parse_Texture();
Post_Textures(Textures[i]);
Parse_End();
Parse_Comma();
}
}
Parse_End();
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if (number_of_vertices == 0)
Error("Vertex vectors not found in mesh2");
/* first make sure we at least have one UV coordinate */
if (number_of_uvcoords == 0)
{
number_of_uvcoords = 1;
UVCoords = reinterpret_cast(POV_MALLOC(number_of_uvcoords*sizeof(MeshUVVector), "triangle mesh data"));
UVCoords[0][U] = 0;
UVCoords[0][V] = 0;
}
/* ------------------- Get the Faces ------------------- */
GET(FACE_INDICES_TOKEN)
Parse_Begin();
/* number faces is mandatory, so we ask how many there are */
number_of_triangles = Parse_Float(); Parse_Comma();
if (number_of_triangles == 0)
{
Error("No triangles in triangle mesh.");
}
/* allocate memory for triangles */
Triangles = reinterpret_cast(POV_MALLOC(number_of_triangles*sizeof(MESH_TRIANGLE), "triangle mesh data"));
/* start reading triangles */
for(i=0; i=number_of_vertices || b>=number_of_vertices ||
c>=number_of_vertices)
{
Error("Mesh face index out of range.");
}
/* Init triangle. */
Object->Init_Mesh_Triangle(&Triangles[i]);
/* assign the vertices */
Triangles[i].P1 = a;
Triangles[i].P2 = b;
Triangles[i].P3 = c;
/* look for a texture index */
EXPECT
CASE_FLOAT
Triangles[i].Texture = Parse_Float(); Parse_Comma();
if (Triangles[i].Texture >= number_of_textures ||
Triangles[i].Texture < 0)
Error("Texture index out of range in mesh2.");
EXIT
END_CASE
OTHERWISE
Triangles[i].Texture = -1;
fully_textured = false;
EXIT
UNGET
END_CASE
END_EXPECT
/* look for a texture index */
EXPECT
CASE_FLOAT
Triangles[i].Texture2 = Parse_Float(); Parse_Comma();
if (Triangles[i].Texture2 >= number_of_textures ||
Triangles[i].Texture2 < 0)
Error("Texture index out of range in mesh2.");
Triangles[i].ThreeTex = true;
EXIT
END_CASE
OTHERWISE
Triangles[i].Texture2 = -1;
EXIT
UNGET
END_CASE
END_EXPECT
/* look for a texture index */
EXPECT
CASE_FLOAT
Triangles[i].Texture3 = Parse_Float(); Parse_Comma();
if (Triangles[i].Texture3 >= number_of_textures ||
Triangles[i].Texture3 < 0)
Error("Texture index out of range in mesh2.");
Triangles[i].ThreeTex = true;
EXIT
END_CASE
OTHERWISE
Triangles[i].Texture3 = -1;
EXIT
UNGET
END_CASE
END_EXPECT
}
Parse_End();
/* now we get the uv_indices & normal_indices in either order */
EXPECT
CASE(UV_INDICES_TOKEN)
if (found_uv_indices)
{
Error("Only one uv_indices section is allowed in mesh2");
}
found_uv_indices = true;
Parse_Begin();
if (Parse_Float() != number_of_triangles)
Error("Number of uv indices must equal number of faces.");
Parse_Comma();
for (i=0; i=number_of_uvcoords || b>=number_of_uvcoords ||
c>=number_of_uvcoords)
{
Error("Mesh UV index out of range.");
}
/* assign the uv coordinate */
Triangles[i].UV1 = a;
Triangles[i].UV2 = b;
Triangles[i].UV3 = c;
}
Parse_End();
/*EXIT*/
END_CASE
/*
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
EXPECT
*/
CASE(NORMAL_INDICES_TOKEN)
if (found_normal_indices)
{
Error("Only one normal_indices section is allowed in mesh2");
}
found_normal_indices = true;
Parse_Begin();
/*
Change - if fewer normals than triangles, then no problem - the
rest will be flat triangles.
if (Parse_Float() != number_of_triangles)
Error("Number of normal indices must equal number of faces.");
*/
number_of_normal_indices = Parse_Float();
if (number_of_normal_indices > number_of_triangles)
Error("Number of normal indices cannot be more than the number of faces.");
Parse_Comma();
for (i=0; i=number_of_normals || b>=number_of_normals ||
c>=number_of_normals)
{
Error("Mesh normal index out of range.");
}
/* assign the uv coordinate */
Triangles[i].N1 = a;
Triangles[i].N2 = b;
Triangles[i].N3 = c;
}
Parse_End();
/*EXIT*/
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* ----------------------------------------------------- */
/* ----------------------------------------------------- */
EXPECT
CASE(INSIDE_VECTOR_TOKEN)
Parse_Vector(Inside_Vect);
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if (fully_textured)
Object->Type |= TEXTURED_OBJECT;
if (!found_uv_indices)
{
if (number_of_uvcoords==number_of_vertices)
{
for (i=0; i(POV_MALLOC(number_of_triangles*sizeof(MeshVector), "triangle mesh data"));
else
Normals = reinterpret_cast(POV_REALLOC(Normals, (number_of_normals+number_of_triangles)*sizeof(MeshVector), "triangle mesh data"));
for (i=0; i 0, then the first triangles
are smooth and the rest are flat */
if (i EPSILON) || (fabs(l2) > EPSILON))
{
/* Smooth triangle. */
Object->Compute_Mesh_Triangle(&Triangles[i], true, P1, P2, P3, N);
Triangles[i].Smooth = true;
}
else
{
/* Flat triangle. */
Object->Compute_Mesh_Triangle(&Triangles[i], false, P1, P2, P3, N);
}
}
else
{
/* Flat triangle. */
Object->Compute_Mesh_Triangle(&Triangles[i], false, P1, P2, P3, N);
}
/* assign the triangle normal that we just computed */
Triangles[i].Normal_Ind = i+number_of_normals;
Normals[i+number_of_normals] = MeshVector(N);
}
/* now remember how many normals we really have */
number_of_normals += number_of_triangles;
/* ----------------------------------------------------- */
/* Init triangle mesh data. */
Object->Data = reinterpret_cast(POV_MALLOC(sizeof(MESH_DATA), "triangle mesh data"));
Object->Data->References = 1;
Object->Data->Tree = NULL;
/* NK 1998 */
/*YS* 31/12/1999 */
if( (fabs(Inside_Vect[X]) < EPSILON) && (fabs(Inside_Vect[Y]) < EPSILON) && (fabs(Inside_Vect[Z]) < EPSILON))
{
Object->has_inside_vector=false;
Object->Type |= PATCH_OBJECT;
}
else
{
Object->Data->Inside_Vect = Inside_Vect.normalized();
Object->has_inside_vector=true;
Object->Type &= ~PATCH_OBJECT;
}
/*YS*/
/* copy pointers to normals, triangles, textures, and vertices. */
Object->Data->Normals = Normals;
Object->Data->Triangles = Triangles;
Object->Data->Vertices = Vertices;
Object->Data->UVCoords = UVCoords;
/* [LSK] Removed "Data->" */
Object->Textures = Textures;
/* copy number of for normals, textures, triangles and vertices. */
Object->Data->Number_Of_Normals = number_of_normals;
Object->Data->Number_Of_Triangles = number_of_triangles;
Object->Data->Number_Of_Vertices = number_of_vertices;
Object->Data->Number_Of_UVCoords = number_of_uvcoords;
Object->Number_Of_Textures = number_of_textures;
if (number_of_textures)
{
Set_Flag(Object, MULTITEXTURE_FLAG);
}
/* Create bounding box. */
Object->Compute_BBox();
/* Parse object modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
/* Create bounding box tree. */
Object->Build_Mesh_BBox_Tree();
/*
Render_Info("Mesh2: %ld bytes: %ld vertices, %ld normals, %ld textures, %ld triangles, %ld uv-coords\n",
Object->Data->Number_Of_Normals*sizeof(MeshVector)+
Object->Number_Of_Textures*sizeof(TEXTURE *)+
Object->Data->Number_Of_Triangles*sizeof(MESH_TRIANGLE)+
Object->Data->Number_Of_Vertices*sizeof(MeshVector)+
Object->Data->Number_Of_UVCoords*sizeof(MeshUVVector),
Object->Data->Number_Of_Vertices,
Object->Data->Number_Of_Normals,
Object->Number_Of_Textures,
Object->Data->Number_Of_Triangles,
Object->Data->Number_Of_UVCoords);
*/
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Mesh_Texture
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* OBJECT
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Read an individual triangle mesh texture.
*
* CHANGES
*
* Feb 1995 : Creation.
*
******************************************************************************/
TEXTURE *Parser::Parse_Mesh_Texture (TEXTURE **t2, TEXTURE **t3)
{
TEXTURE *Texture;
Texture = NULL;
EXPECT
CASE(TEXTURE_TOKEN)
Parse_Begin();
GET(TEXTURE_ID_TOKEN);
Texture = reinterpret_cast(Token.Data);
Parse_End();
END_CASE
/* NK */
CASE(TEXTURE_LIST_TOKEN)
Parse_Begin();
GET(TEXTURE_ID_TOKEN);
Texture = reinterpret_cast(Token.Data);
Parse_Comma();
GET(TEXTURE_ID_TOKEN);
*t2 = reinterpret_cast(Token.Data);
Parse_Comma();
GET(TEXTURE_ID_TOKEN);
*t3 = reinterpret_cast(Token.Data);
Parse_End();
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
return(Texture);
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Ovus
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* OBJECT
*
* AUTHOR
*
* Jerome Grimbert
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Jul 2010 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Ovus()
{
DBL distance;
Ovus *Object;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast(Object));
}
Object = new Ovus();
Object->BottomRadius = Parse_Float(); /* Bottom radius */
Parse_Comma();
Object->TopRadius = Parse_Float(); /* Top radius */
/*
** Pre-compute the important values
*/
if ((Object->TopRadius < 0)||(Object->BottomRadius < 0))
{
Error("Both Ovus radii must be positive");
}
if (Object->TopRadius < 2.0 * Object->BottomRadius)
{
if (Object->BottomRadius > Object->TopRadius)
{
Object->ConnectingRadius = 2.0 * Object->BottomRadius;
Object->VerticalPosition = 2.0 * Object->TopRadius - Object->BottomRadius - (Object->TopRadius * Object->TopRadius / (2.0 * Object->BottomRadius) );
Object->HorizontalPosition = sqrt((Object->BottomRadius)*(Object->BottomRadius) -(Object->VerticalPosition)*(Object->VerticalPosition));
Object->BottomVertical = -Object->VerticalPosition;
distance = Object->ConnectingRadius - Object->TopRadius;
Object->TopVertical = ((Object->BottomRadius - Object->VerticalPosition) * Object->TopRadius / distance ) + Object->BottomRadius;
} else {
Object->ConnectingRadius = 2.0 * Object->TopRadius;
Object->VerticalPosition = - 2.0 * Object->TopRadius + Object->BottomRadius + (1.5 * Object->TopRadius * Object->TopRadius / Object->BottomRadius);
Object->HorizontalPosition = sqrt((Object->TopRadius)*(Object->TopRadius) - ((Object->VerticalPosition - Object->BottomRadius) * (Object->VerticalPosition - Object->BottomRadius)));
Object->TopVertical = 2.0 * Object->BottomRadius - Object->VerticalPosition;
distance = Object->ConnectingRadius - Object->BottomRadius;
Object->BottomVertical = -Object->VerticalPosition * Object->BottomRadius / distance;
}
Object->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
else
{
PossibleError("Ovus second radius should be less than twice first radius\nSubstituing a sphere to ovus as it would be identical & simpler");
Sphere * Replacement;
Replacement = new Sphere();
Replacement->Center[X]=0;
Replacement->Center[Y]=Object->BottomRadius;
Replacement->Center[Z]=0;
Replacement->Radius = Object->TopRadius;
delete Object;
Replacement->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Replacement));
return (reinterpret_cast(Replacement));
}
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Parametric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Parametric(void)
{
Parametric *Object;
DBL temp;
char PrecompFlag = 0;
int PrecompDepth = 1;
Vector2d tempUV;
Parse_Begin();
if((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Parametric();
Object->vm = sceneData->functionVM;
EXPECT
CASE(FUNCTION_TOKEN)
Object->Function[0]= Parse_Function();
EXIT
END_CASE
OTHERWISE
Object->Function[0]= Parse_FunctionContent();
EXIT
END_CASE
END_EXPECT
Parse_Comma();
EXPECT
CASE(FUNCTION_TOKEN)
Object->Function[1]= Parse_Function();
EXIT
END_CASE
OTHERWISE
Object->Function[1]= Parse_FunctionContent();
EXIT
END_CASE
END_EXPECT
Parse_Comma();
EXPECT
CASE(FUNCTION_TOKEN)
Object->Function[2]= Parse_Function();
EXIT
END_CASE
OTHERWISE
Object->Function[2]= Parse_FunctionContent();
EXIT
END_CASE
END_EXPECT
Parse_UV_Vect(tempUV);
Object->umin = tempUV[U];
Object->vmin = tempUV[V];
Parse_Comma();
Parse_UV_Vect(tempUV);
Object->umax = tempUV[U];
Object->vmax = tempUV[V];
if(Object->umin>Object->umax)
{
temp = Object->umin;
Object->umin = Object->umax;
Object->umax = temp;
}
if(Object->vmin>Object->vmax)
{
temp = Object->vmin;
Object->vmin = Object->vmax;
Object->vmax = temp;
}
EXPECT
CASE(ACCURACY_TOKEN)
Object->accuracy= Parse_Float();
END_CASE
CASE(MAX_GRADIENT_TOKEN)
Object->max_gradient = Parse_Float();
END_CASE
CASE(PRECOMPUTE_TOKEN)
PrecompDepth= Parse_Float();
Parse_Comma();
EXPECT
CASE(VECTOR_FUNCT_TOKEN)
if(Token.Function_Id != X_TOKEN)
{
UNGET
}
else
PrecompFlag |= 1;
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_Comma();
EXPECT
CASE(VECTOR_FUNCT_TOKEN)
if(Token.Function_Id != Y_TOKEN)
{
UNGET
}
else
PrecompFlag |= 2;
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_Comma();
EXPECT
CASE(VECTOR_FUNCT_TOKEN)
if(Token.Function_Id != Z_TOKEN)
{
UNGET
}
else
PrecompFlag |= 4;
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
END_CASE
CASE(CONTAINED_BY_TOKEN)
// TODO - same code as for isosurface
Parse_Begin();
{
int Exit_Flag2 = false;
while (!Exit_Flag2)
{
Get_Token();
switch(Token.Token_Id)
{
CASE(BOX_TOKEN)
Object->container = shared_ptr(new ContainedByBox());
Parse_Begin();
Parse_Vector(dynamic_cast(Object->container.get())->corner1);
Parse_Comma();
Parse_Vector(dynamic_cast(Object->container.get())->corner2);
Parse_End();
if (dynamic_cast(Object->container.get())->corner1.x() > dynamic_cast(Object->container.get())->corner2.x())
{
temp = dynamic_cast(Object->container.get())->corner1.x();
dynamic_cast(Object->container.get())->corner1.x() = dynamic_cast(Object->container.get())->corner2.x();
dynamic_cast(Object->container.get())->corner2.x() = temp;
}
if (dynamic_cast(Object->container.get())->corner1.y() > dynamic_cast(Object->container.get())->corner2.y())
{
temp = dynamic_cast(Object->container.get())->corner1.y();
dynamic_cast(Object->container.get())->corner1.y() = dynamic_cast(Object->container.get())->corner2.y();
dynamic_cast(Object->container.get())->corner2.y() = temp;
}
if (dynamic_cast(Object->container.get())->corner1.z() > dynamic_cast(Object->container.get())->corner2.z())
{
temp = dynamic_cast(Object->container.get())->corner1.z();
dynamic_cast(Object->container.get())->corner1.z() = dynamic_cast(Object->container.get())->corner2.z();
dynamic_cast(Object->container.get())->corner2.z() = temp;
}
if (Object->Trans != NULL)
Object->Compute_BBox();
Exit_Flag2 = true;
END_CASE
CASE(SPHERE_TOKEN)
Object->container = shared_ptr(new ContainedBySphere());
Parse_Begin();
Parse_Vector(dynamic_cast(Object->container.get())->center);
Parse_Comma();
dynamic_cast(Object->container.get())->radius = Parse_Float();
Parse_End();
Make_BBox(Object->BBox,
dynamic_cast(Object->container.get())->center.x() - dynamic_cast(Object->container.get())->radius,
dynamic_cast(Object->container.get())->center.y() - dynamic_cast(Object->container.get())->radius,
dynamic_cast(Object->container.get())->center.z() - dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius,
2.0 * dynamic_cast(Object->container.get())->radius);
if (Object->Trans != NULL)
Object->Compute_BBox();
Exit_Flag2 = true;
END_CASE
OTHERWISE
UNGET
Exit_Flag2 = true;
END_CASE
}
}
}
Parse_End();
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Parse_Object_Mods(reinterpret_cast(Object));
if(PrecompFlag != 0)
Object->Precompute_Parametric_Values(PrecompFlag, PrecompDepth, fnVMContext);
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Plane ()
{
DBL len;
Plane *Object;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Plane();
Parse_Vector(Object->Normal_Vector); Parse_Comma();
len = Object->Normal_Vector.length();
if (len < EPSILON)
{
Error("Degenerate plane normal.");
}
Object->Normal_Vector /= len;
Object->Distance = -Parse_Float();
Object->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Poly (int order)
{
Poly *Object;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
if (order == 0)
{
order = (int)Parse_Float(); Parse_Comma();
if (order < 2 || order > MAX_ORDER)
Error("Order of poly is out of range.");
}
Object = new Poly(order);
Parse_Coeffs(Object->Order, &(Object->Coeffs[0]));
Object->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Polynom ()
{
Poly *Object;
unsigned int x,y,z;
int order;
DBL value;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
order = (int)Parse_Float(); Parse_Comma();
if (order < 2 || order > MAX_ORDER)
{
Error("Order of polynom is out of range.");
}
Object = new Poly(order);
EXPECT
CASE (XYZ_TOKEN)
GET (LEFT_PAREN_TOKEN);
x = (unsigned int)Parse_Float();
Parse_Comma();
y = (unsigned int)Parse_Float();
Parse_Comma();
z = (unsigned int)Parse_Float();
GET (RIGHT_PAREN_TOKEN);
GET (COLON_TOKEN);
value = Parse_Float();
if (!Object->Set_Coeff(x,y,z,value))
{
Error("Coefficient of polynom is out of range.");
}
Parse_Comma();
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Object->Compute_BBox();
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Polygon
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* May 1994 : Creation.
*
* Oct 1994 : Modified to use new polygon data structure. [DB]
*
******************************************************************************/
ObjectPtr Parser::Parse_Polygon()
{
int i, closed = false;
int Number;
Polygon *Object;
Vector3d *Points;
Vector3d P;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast(Object));
}
Object = new Polygon();
Number = (int)Parse_Float();
if (Number < 3)
{
Error("Polygon needs at least three points.");
}
Points = reinterpret_cast(POV_MALLOC((Number+1)*sizeof(Vector3d), "temporary polygon points"));
for (i = 0; i < Number; i++)
{
Parse_Comma();
Parse_Vector(Points[i]);
}
/* Check for closed polygons. */
P = Points[0];
for (i = 1; i < Number; i++)
{
closed = false;
if ((fabs(P[X] - Points[i][X]) < EPSILON) &&
(fabs(P[Y] - Points[i][Y]) < EPSILON) &&
(fabs(P[Z] - Points[i][Z]) < EPSILON))
{
// force almost-identical vertices to be /exactly/ identical,
// to make processing easier later
Points[i] = P;
i++;
if (i < Number)
{
P = Points[i];
}
closed = true;
}
}
if (!closed)
{
Warning("Polygon not closed. Closing it.");
Points[Number] = P;
Number++;
}
Object->Compute_Polygon(Number, Points);
POV_FREE (Points);
Parse_Object_Mods (reinterpret_cast(Object));
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Prism
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Prism()
{
int i, closed = false;
DBL h;
int loopStart = 0;
Prism *Object;
Vector2d *Points;
Vector2d P;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast(Object));
}
Object = new Prism();
/*
* Determine kind of spline used (linear, quadratic, cubic)
* and type of sweeping (linear, conic).
*/
EXPECT
CASE(LINEAR_SPLINE_TOKEN)
Object->Spline_Type = LINEAR_SPLINE;
END_CASE
CASE(QUADRATIC_SPLINE_TOKEN)
Object->Spline_Type = QUADRATIC_SPLINE;
END_CASE
CASE(CUBIC_SPLINE_TOKEN)
Object->Spline_Type = CUBIC_SPLINE;
END_CASE
CASE(BEZIER_SPLINE_TOKEN)
Object->Spline_Type = BEZIER_SPLINE;
END_CASE
CASE(LINEAR_SWEEP_TOKEN)
Object->Sweep_Type = LINEAR_SWEEP;
END_CASE
CASE(CONIC_SWEEP_TOKEN)
Object->Sweep_Type = CONIC_SWEEP;
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Read prism heights. */
Object->Height1 = Parse_Float(); Parse_Comma();
Object->Height2 = Parse_Float(); Parse_Comma();
if (Object->Height1 > Object->Height2)
{
h = Object->Height1;
Object->Height1 = Object->Height2;
Object->Height2 = h;
}
/* Get number of points = number of segments. */
Object->Number = (int)Parse_Float();
switch (Object->Spline_Type)
{
case LINEAR_SPLINE :
if (Object->Number < 3)
{
Error("Prism with linear splines must have at least three points.");
}
break;
case QUADRATIC_SPLINE :
if (Object->Number < 5)
{
Error("Prism with quadratic splines must have at least five points.");
}
break;
case CUBIC_SPLINE :
if (Object->Number < 6)
{
Error("Prism with cubic splines must have at least six points.");
}
break;
case BEZIER_SPLINE :
if ((Object->Number & 3) != 0)
{
Error("Prism with Bezier splines must have four points per segment.");
}
break;
}
/* Allocate Object->Number points for the prism. */
Points = reinterpret_cast(POV_MALLOC((Object->Number+1) * sizeof(Vector2d), "temporary prism points"));
/* Read points (x, y : coordinate of 2d point; z : not used). */
for (i = 0; i < Object->Number; i++)
{
Parse_Comma();
Parse_UV_Vect(Points[i]);
}
/* Closed or not closed that's the question. */
EXPECT
CASE(OPEN_TOKEN)
Clear_Flag(Object, CLOSED_FLAG);
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* Check for closed prism. */
if ((Object->Spline_Type == LINEAR_SPLINE) ||
(Object->Spline_Type == QUADRATIC_SPLINE) ||
(Object->Spline_Type == CUBIC_SPLINE))
{
switch (Object->Spline_Type)
{
case LINEAR_SPLINE :
i = 1;
P = Points[0];
break;
case QUADRATIC_SPLINE :
case CUBIC_SPLINE :
i = 2;
P = Points[1];
break;
}
for (; i < Object->Number; i++)
{
closed = false;
if ((fabs(P[X] - Points[i][X]) < EPSILON) &&
(fabs(P[Y] - Points[i][Y]) < EPSILON))
{
switch (Object->Spline_Type)
{
case LINEAR_SPLINE :
i++;
if (i < Object->Number)
{
P = Points[i];
}
break;
case QUADRATIC_SPLINE :
i += 2;
if (i < Object->Number)
{
P = Points[i];
}
break;
case CUBIC_SPLINE :
i += 3;
if (i < Object->Number)
{
P = Points[i];
}
break;
}
closed = true;
}
}
}
else
{
closed = true;
loopStart = 0;
for (i = 4; i < Object->Number; i += 4)
{
if ((fabs(Points[i][X] - Points[i-1][X]) > EPSILON) ||
(fabs(Points[i][Y] - Points[i-1][Y]) > EPSILON))
{
//. this is a different point. Check if we have a loop.
if ((fabs(Points[i-1][X] - Points[loopStart][X]) > EPSILON) ||
(fabs(Points[i-1][Y] - Points[loopStart][Y]) > EPSILON))
{
closed = false;
break;
}
loopStart = i;
}
}
if ((fabs(Points[Object->Number-1][X] - Points[loopStart][X]) > EPSILON) ||
(fabs(Points[Object->Number-1][Y] - Points[loopStart][Y]) > EPSILON))
{
closed = false;
}
}
if (!closed)
{
if (Object->Spline_Type == LINEAR_SPLINE)
{
Points[Object->Number] = P;
Object->Number++;
Warning("Linear prism not closed. Closing it.");
}
else
{
Set_Flag(Object, DEGENERATE_FLAG);
Warning("Prism not closed. Ignoring it.");
}
}
/* Compute spline segments. */
Object->Compute_Prism(Points, GetParserDataPtr());
/* Compute bounding box. */
Object->Compute_BBox();
/* Parse object's modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
/* Destroy temporary points. */
POV_FREE (Points);
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Quadric ()
{
Vector3d Min, Max;
Quadric *Object;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new Quadric();
Parse_Vector(Object->Square_Terms); Parse_Comma();
Parse_Vector(Object->Mixed_Terms); Parse_Comma();
Parse_Vector(Object->Terms); Parse_Comma();
Object->Constant = Parse_Float();
Min = Vector3d(-BOUND_HUGE);
Max = Vector3d(BOUND_HUGE);
Object->Compute_BBox(Min, Max);
Parse_Object_Mods (reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Smooth_Triangle ()
{
SmoothTriangle *Object;
short degen;
DBL vlen;
degen=false;
Parse_Begin ();
if ( (Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new SmoothTriangle();
Parse_Vector (Object->P1); Parse_Comma();
Parse_Vector (Object->N1); Parse_Comma();
vlen = Object->N1.length();
if (vlen == 0.0)
degen=true;
else
Object->N1 /= vlen;
Parse_Vector (Object->P2); Parse_Comma();
Parse_Vector (Object->N2); Parse_Comma();
vlen = Object->N2.length();
if(vlen == 0.0)
degen=true;
else
Object->N2 /= vlen;
Parse_Vector (Object->P3); Parse_Comma();
Parse_Vector (Object->N3);
vlen = Object->N3.length();
if(vlen == 0.0)
degen=true;
else
Object->N3.normalize();
if(!degen)
degen = !Object->Compute_Triangle();
if(degen)
Warning("Degenerate triangle. Please remove.");
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Sor
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Read a surface of revolution primitive.
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Sor()
{
int i;
Sor *Object;
Vector2d *Points;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast(Object));
}
Object = new Sor();
/* Get number of points. */
Object->Number = (int)Parse_Float();
if (Object->Number <4)
{
Error("Surface of revolution must have at least four points.");
}
/* Get temporary points describing the rotated curve. */
Points = reinterpret_cast(POV_MALLOC(Object->Number*sizeof(Vector2d), "temporary surface of revolution points"));
/* Read points (x : radius; y : height; z : not used). */
for (i = 0; i < Object->Number; i++)
{
Parse_Comma();
Parse_UV_Vect(Points[i]);
if ((Points[i][X] < 0.0) ||
((i > 1 ) && (i < Object->Number - 1) && (Points[i][Y] <= Points[i-1][Y])))
{
Error("Incorrect point in surface of revolution.");
}
}
/* Closed or not closed that's the question. */
EXPECT
CASE(OPEN_TOKEN)
Clear_Flag(Object, CLOSED_FLAG);
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
/* There are Number-3 segments! */
Object->Number -= 3;
/* Compute spline segments. */
Object->Compute_Sor(Points, GetParserDataPtr());
/* Compute bounding box. */
Object->Compute_BBox();
/* Parse object's modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
/* Destroy temporary points. */
POV_FREE (Points);
if (Object->Spline->BCyl->number > sceneData->Max_Bounding_Cylinders)
{
SceneThreadData *td = GetParserDataPtr();
sceneData->Max_Bounding_Cylinders = Object->Spline->BCyl->number;
td->BCyl_Intervals.reserve(4*sceneData->Max_Bounding_Cylinders);
td->BCyl_RInt.reserve(2*sceneData->Max_Bounding_Cylinders);
td->BCyl_HInt.reserve(2*sceneData->Max_Bounding_Cylinders);
}
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Sphere()
{
Sphere *Object;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return (reinterpret_cast(Object));
}
Object = new Sphere();
Parse_Vector(Object->Center);
Parse_Comma();
Object->Radius = Parse_Float();
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Sphere_Sweep
*
* INPUT
*
* -
*
* OUTPUT
*
* -
*
* RETURNS
*
* Object
*
* AUTHOR
*
* Jochen Lippert
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
ObjectPtr Parser::Parse_Sphere_Sweep()
{
SphereSweep *Object;
int i;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
return (reinterpret_cast(Object));
Object = new SphereSweep();
/* Get type of interpolation */
EXPECT
CASE(LINEAR_SPLINE_TOKEN)
Object->Interpolation = LINEAR_SPHERE_SWEEP;
EXIT
END_CASE
CASE(CUBIC_SPLINE_TOKEN)
Object->Interpolation = CATMULL_ROM_SPLINE_SPHERE_SWEEP;
EXIT
END_CASE
CASE(B_SPLINE_TOKEN)
Object->Interpolation = B_SPLINE_SPHERE_SWEEP;
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
if (Object->Interpolation == -1)
{
Error("Invalid type of interpolation.");
}
Parse_Comma();
/* Get number of modeling spheres */
Object->Num_Modeling_Spheres = (int)Parse_Float();
if ((Object->Num_Modeling_Spheres < 2) || (Object->Interpolation != LINEAR_SPHERE_SWEEP && Object->Num_Modeling_Spheres < 4))
Error("Too few modeling spheres for interpolation type.");
Object->Modeling_Sphere =
reinterpret_cast(POV_MALLOC(Object->Num_Modeling_Spheres * sizeof(SPHSWEEP_SPH),
"sphere sweep modeling spheres"));
for (i = 0; i < Object->Num_Modeling_Spheres; i++)
{
Parse_Comma();
Parse_Vector(Object->Modeling_Sphere[i].Center);
Parse_Comma();
Object->Modeling_Sphere[i].Radius = Parse_Float();
}
EXPECT
CASE(TOLERANCE_TOKEN)
Object->Depth_Tolerance = Parse_Float();
EXIT
END_CASE
OTHERWISE
UNGET
EXIT
END_CASE
END_EXPECT
Object->Compute();
Object->Compute_BBox();
Parse_Object_Mods(reinterpret_cast(Object));
return (reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Superellipsoid
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* ObjectPtr -
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Read a superellipsoid primitive.
*
* CHANGES
*
* Oct 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Superellipsoid()
{
Vector2d V1;
Superellipsoid *Object;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast(Object));
}
Object = new Superellipsoid();
Parse_UV_Vect(V1);
/* The x component is e, the y component is n. */
Object->Power[X] = 2.0 / V1[X];
Object->Power[Y] = V1[X] / V1[Y];
Object->Power[Z] = 2.0 / V1[Y];
/* Compute bounding box. */
Object->Compute_BBox();
/* Parse object's modifiers. */
Parse_Object_Mods(reinterpret_cast(Object));
return(reinterpret_cast(Object));
}
/*****************************************************************************
*
* FUNCTION
*
* Parse_Torus
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* OBJECT
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Jul 1994 : Creation.
*
******************************************************************************/
ObjectPtr Parser::Parse_Torus()
{
Torus *Object;
Parse_Begin();
if ((Object = reinterpret_cast(Parse_Object_Id())) != NULL)
{
return(reinterpret_cast