diff options
Diffstat (limited to 'kpovmodeler/pmpovrayparser.cpp')
-rw-r--r-- | kpovmodeler/pmpovrayparser.cpp | 7213 |
1 files changed, 7213 insertions, 0 deletions
diff --git a/kpovmodeler/pmpovrayparser.cpp b/kpovmodeler/pmpovrayparser.cpp new file mode 100644 index 00000000..88bd8393 --- /dev/null +++ b/kpovmodeler/pmpovrayparser.cpp @@ -0,0 +1,7213 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2003 by Andreas Zehender + email : zehender@kde.org +************************************************************************** + +************************************************************************** +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +**************************************************************************/ + + +#include "pmpovrayparser.h" + +#include <klocale.h> +#include <qvaluelist.h> + +#include "pmpart.h" +#include "pmscanner.h" +#include "pmtokens.h" + +#include "pmcolor.h" +#include "pmallobjects.h" +#include "pmprototypemanager.h" +#include "pmxmlhelper.h" + + +PMPovrayParser::PMPovrayParser( PMPart* part, QIODevice* dev ) + : PMParser( part, dev ) +{ + init( ); +} + +PMPovrayParser::PMPovrayParser( PMPart* part, const QByteArray& array ) + : PMParser( part, array ) +{ + init( ); +} + +PMPovrayParser::~PMPovrayParser( ) +{ + if( m_pScanner ) + delete m_pScanner; +} + +void PMPovrayParser::init( ) +{ + m_pScanner = new PMScanner( m_pDevice ); + m_consumedTokens = 0; + m_skippedComments.setAutoDelete( true ); + m_bLastPMCommentEmpty = true; +} + + +void PMPovrayParser::nextToken( ) +{ + m_token = m_pScanner->nextToken( ); + m_consumedTokens++; + setCurrentLine( m_pScanner->currentLine( ) ); + + if( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK ) + || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) ) + { + // create the objects (string) only if necessary + PMComment* c; + int lastCommentLine = -2; + QString commentText; + + while( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK ) + || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) ) + { + switch( m_token ) + { + case SCANNER_ERROR_TOK: + printError( m_pScanner->error( ) ); + lastCommentLine = -2; + break; + case LINE_COMMENT_TOK: + commentText = m_pScanner->sValue( ); + if( lastCommentLine == ( m_pScanner->currentLine( ) - 1 ) ) + { + c = m_skippedComments.last( ); + if( c ) + c->setText( c->text( ) + '\n' + commentText ); + else + { + c = new PMComment( m_pPart, commentText ); + m_skippedComments.append( c ); + } + } + else + { + c = new PMComment( m_pPart, m_pScanner->sValue( ) ); + m_skippedComments.append( c ); + } + lastCommentLine = m_pScanner->currentLine( ); + break; + case COMMENT_TOK: + c = new PMComment( m_pPart, m_pScanner->sValue( ) ); + m_skippedComments.append( c ); + lastCommentLine = -2; + break; + case PMNAME_TOK: + // Special comment + m_lastPMComment = m_pScanner->sValue( ); + m_bLastPMCommentEmpty = false; + lastCommentLine = -2; + break; + default: + lastCommentLine = -2; + break; + } + + m_token = m_pScanner->nextToken( ); + m_consumedTokens++; + } + } +} + +bool PMPovrayParser::isTrue( ) const +{ + if( ( m_token == ON_TOK ) || ( m_token == TRUE_TOK ) || ( m_token == YES_TOK ) ) + return true; + return false; +} + +bool PMPovrayParser::isFalse( ) const +{ + if( ( m_token == OFF_TOK ) || ( m_token == FALSE_TOK ) || ( m_token == NO_TOK ) ) + return true; + return false; +} + +void PMPovrayParser::topParse( ) +{ + nextToken( ); + + do + { + if( !parseChildObjects( 0 ) ) + m_token = EOF_TOK; + if( m_token != EOF_TOK ) + { + printUnexpected( m_pScanner->sValue( ) ); + nextToken( ); + } + } + while( m_token != EOF_TOK ); + + if( errors( ) || warnings( ) ) + printMessage( PMMSpecialRawComment ); +} + +bool PMPovrayParser::parseBool( ) +{ + if( isFalse( ) ) + { + nextToken( ); + return false; + } + if( isTrue( ) ) + { + nextToken( ); + return true; + } + + PMValue v; + + if( parseNumericExpression( v, true ) ) + { + switch( v.type( ) ) + { + case PMVFloat: + return v.floatValue( ) > 0.0; + break; + case PMVVector: + return ( v.vector( ) )[0] > 0.0; + break; + default: + printError( i18n( "Boolean expression expected" ) ); + break; + } + } + + return true; +} + +bool PMPovrayParser::parseChildObjects( PMCompositeObject* parent, + int max /* = -1 */ ) +{ + PMObject* child = 0; + bool finished = false; + bool error = false; + bool noChild = false; + int numParsed = 0; + + do + { + if( !m_bLastPMCommentEmpty && parent ) + { + if( parent->isA( "NamedObject" ) ) + ( ( PMNamedObject* ) parent )->setName( m_lastPMComment ); + m_bLastPMCommentEmpty = true; + } + if( m_skippedComments.count( ) > 0 ) + child = m_skippedComments.take( 0 ); + else + { + child = 0; + noChild = false; + + // some objects + switch( m_token ) + { + case UNION_TOK: + case DIFFERENCE_TOK: + case INTERSECTION_TOK: + case MERGE_TOK: + child = new PMCSG( m_pPart ); + error = !parseCSG( ( PMCSG* ) child ); + break; + case BOX_TOK: + child = new PMBox( m_pPart ); + error = !parseBox( ( PMBox* ) child ); + break; + case SPHERE_TOK: + if( ( parent && ( parent->type( ) == "Blob" ) ) + || ( !parent && m_pTopParent + && ( m_pTopParent->type( ) == "Blob" ) ) ) + { + child = new PMBlobSphere( m_pPart ); + error = !parseBlobSphere( ( PMBlobSphere* ) child ); + } + else + { + child = new PMSphere( m_pPart ); + error = !parseSphere( ( PMSphere* ) child ); + } + break; + case CYLINDER_TOK: + if( ( parent && ( parent->type( ) == "Blob" ) ) + || ( !parent && m_pTopParent + && ( m_pTopParent->type( ) == "Blob" ) ) ) + { + child = new PMBlobCylinder( m_pPart ); + error = !parseBlobCylinder( ( PMBlobCylinder* ) child ); + } + else + { + child = new PMCylinder( m_pPart ); + error = !parseCylinder( ( PMCylinder* ) child ); + } + break; + case CONE_TOK: + child = new PMCone( m_pPart ); + error = !parseCone( ( PMCone* ) child ); + break; + case TORUS_TOK: + child = new PMTorus( m_pPart ); + error = !parseTorus( ( PMTorus* ) child ); + break; + case BLOB_TOK: + child = new PMBlob( m_pPart ); + error = !parseBlob( ( PMBlob* ) child ); + break; + case COMPONENT_TOK: + child = new PMBlobSphere( m_pPart ); + error = !parseBlobComponent( ( PMBlobSphere* ) child ); + break; + case HEIGHT_FIELD_TOK: + child = new PMHeightField( m_pPart ); + error = !parseHeightField( ( PMHeightField* ) child ); + break; + case TEXT_TOK: + child = new PMText( m_pPart ); + error = !parseText( ( PMText* ) child ); + break; + case JULIA_FRACTAL_TOK: + child = new PMJuliaFractal( m_pPart ); + error = !parseJuliaFractal( ( PMJuliaFractal* ) child ); + break; + case PLANE_TOK: + child = new PMPlane( m_pPart ); + error = !parsePlane( ( PMPlane* ) child ); + break; + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + child = new PMPolynom( m_pPart ); + error = !parsePolynom( ( PMPolynom* ) child ); + break; + case BICUBIC_PATCH_TOK: + child = new PMBicubicPatch( m_pPart ); + error = !parseBicubicPatch( ( PMBicubicPatch* ) child ); + break; + case DISC_TOK: + child = new PMDisc( m_pPart ); + error = !parseDisc( ( PMDisc* ) child ); + break; + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + child = new PMTriangle( m_pPart ); + error = !parseTriangle( ( PMTriangle* ) child ); + break; + case LATHE_TOK: + child = new PMLathe( m_pPart ); + error = !parseLathe( ( PMLathe* ) child ); + break; + case PRISM_TOK: + child = new PMPrism( m_pPart ); + error = !parsePrism( ( PMPrism* ) child ); + break; + case SOR_TOK: + child = new PMSurfaceOfRevolution( m_pPart ); + error = !parseSor( ( PMSurfaceOfRevolution* ) child ); + break; + case SUPERELLIPSOID_TOK: + child = new PMSuperquadricEllipsoid( m_pPart ); + error = !parseSqe( ( PMSuperquadricEllipsoid* ) child ); + break; + case CAMERA_TOK: + child = new PMCamera( m_pPart ); + error = !parseCamera( ( PMCamera* ) child ); + break; + case LIGHT_SOURCE_TOK: + child = new PMLight( m_pPart ); + error = !parseLight( ( PMLight* ) child ); + break; + case LOOKS_LIKE_TOK: + child = new PMLooksLike( m_pPart ); + error = !parseLooksLike( ( PMLooksLike* ) child ); + break; + case PROJECTED_THROUGH_TOK: + child = new PMProjectedThrough( m_pPart ); + error = !parseProjectedThrough( ( PMProjectedThrough* ) child ); + break; + case TEXTURE_TOK: + child = new PMTexture( m_pPart ); + error = !parseTexture( ( PMTexture* ) child ); + break; + case AGATE_TOK: + case AVERAGE_TOK: + case BOXED_TOK: + case BOZO_TOK: + case BUMPS_TOK: + case CELLS_TOK: + case CRACKLE_TOK: + case CYLINDRICAL_TOK: + case DENTS_TOK: + case DENSITY_FILE_TOK: + case GRADIENT_TOK: + case GRANITE_TOK: + case JULIA_TOK: + case LEOPARD_TOK: + case MAGNET_TOK: + case MANDEL_TOK: + case MARBLE_TOK: + case ONION_TOK: + case PLANAR_TOK: + case QUILTED_TOK: + case RADIAL_TOK: + case RIPPLES_TOK: + case SLOPE_TOK: + case SPHERICAL_TOK: + case SPIRAL1_TOK: + case SPIRAL2_TOK: + case SPOTTED_TOK: + case WOOD_TOK: + case WAVES_TOK: + case WRINKLES_TOK: + child = new PMPattern( m_pPart ); + { + bool normal = true; + if( parent && ( parent->type( ) != "Normal" ) ) + normal = false; + error = !parsePattern( ( PMPattern* ) child, normal ); + } + break; + case TURBULENCE_TOK: + // Search for a PMPattern in the object's children + child = parent->firstChild( ); + while( child && !child->isA( "Pattern" ) ) + child = child->nextSibling( ); + if( child ) + { + error = !parsePattern( ( PMPattern* ) child ); + child = 0; + noChild = true; + } + else + { + printError( i18n( "Found turbulence without a pattern." ) ); + error = true; + } + break; + case FREQUENCY_TOK: + case PHASE_TOK: + case RAMP_WAVE_TOK: + case TRIANGLE_WAVE_TOK: + case SINE_WAVE_TOK: + case SCALLOP_WAVE_TOK: + case CUBIC_WAVE_TOK: + case POLY_WAVE_TOK: + // Search for a PMBlendMapModifiers in the object's children + child = parent->firstChild( ); + while( child && !child->isA( "BlendMapModifiers" ) ) + child = child->nextSibling( ); + if( child ) + { + error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child ); + child = 0; + noChild = 0; + } + else + { + child = new PMBlendMapModifiers( m_pPart ); + error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child ); + } + break; + case WARP_TOK: + child = new PMWarp( m_pPart ); + error = !parseWarp( ( PMWarp* ) child ); + break; + case PIGMENT_TOK: + child = new PMPigment( m_pPart ); + error = !parsePigment( ( PMPigment* ) child ); + break; + case NORMAL_TOK: + child = new PMNormal( m_pPart ); + error = !parseNormal( ( PMNormal* ) child ); + break; + case NORMAL_MAP_TOK: + child = new PMNormalMap( m_pPart ); + error = !parseNormalMap( ( PMNormalMap* ) child ); + break; + case BUMP_MAP_TOK: + child = new PMBumpMap( m_pPart ); + error = !parseBumpMap( ( PMBumpMap* ) child ); + break; + case SLOPE_MAP_TOK: + child = new PMSlopeMap( m_pPart ); + error = !parseSlopeMap( ( PMSlopeMap* ) child ); + break; + case DENSITY_MAP_TOK: + child = new PMDensityMap( m_pPart ); + error = !parseDensityMap( ( PMDensityMap* ) child ); + break; + case TEXTURE_MAP_TOK: + child = new PMTextureMap( m_pPart ); + error = !parseTextureMap( ( PMTextureMap* ) child ); + break; + case MATERIAL_MAP_TOK: + child = new PMMaterialMap( m_pPart ); + error = !parseMaterialMap( ( PMMaterialMap* ) child ); + break; + case PIGMENT_MAP_TOK: + child = new PMPigmentMap( m_pPart ); + error = !parsePigmentMap( ( PMPigmentMap* ) child ); + break; + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + child = new PMColorMap( m_pPart ); + error = !parseColorMap( ( PMColorMap* ) child ); + break; + case CHECKER_TOK: + case HEXAGON_TOK: + case BRICK_TOK: + { + bool normal = false; + double depth = 0.0; + int expect = 0; + PMListPattern::PMListType type = PMListPattern::ListPatternChecker; + + if( parent && parent->type( ) == "Normal" ) + normal = true; + else if( m_pTopParent && m_pTopParent->type( ) == "Normal" ) + normal = true; + + switch( m_token ) + { + case CHECKER_TOK: + type = PMListPattern::ListPatternChecker; + expect = 2; + break; + case HEXAGON_TOK: + type = PMListPattern::ListPatternHexagon; + expect = 3; + break; + case BRICK_TOK: + type = PMListPattern::ListPatternBrick; + expect = 2; + break; + } + nextToken( ); + + if( normal ) + { + child = new PMNormalList( m_pPart ); + if( parseFloat( depth, true ) ) + ( ( PMNormalList* ) child )->setDepth( depth ); + + if( m_token == NORMAL_TOK ) + error = !parseNormalList( ( PMNormalList* ) child, expect ); + } + else + { + switch( m_token ) + { + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + child = new PMColorList( m_pPart ); + error = !parseColorList( ( PMColorList* ) child, expect ); + break; + case PIGMENT_TOK: + child = new PMPigmentList( m_pPart ); + error = !parsePigmentList( ( PMPigmentList* ) child, expect ); + break; + case TEXTURE_TOK: + child = new PMTextureList( m_pPart ); + error = !parseTextureList( ( PMTextureList* ) child, expect ); + break; + case NORMAL_TOK: + child = new PMNormalList( m_pPart ); + error = !parseNormalList( ( PMNormalList* ) child, expect ); + break; + case DENSITY_TOK: + child = new PMDensityList( m_pPart ); + error = !parseDensityList( ( PMDensityList* ) child, expect ); + break; + default: + printError( i18n( "Invalid list member." ) ); + error = true; + } + } + + if( child ) + { + ( ( PMListPattern* ) child )->setListType( type ); + + int oldConsumed; + double num = 0; + PMVector vector; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case MORTAR_TOK: + nextToken( ); + if( !parseFloat( num ) ) + return false; + ( ( PMListPattern* ) child )->setMortar( num ); + break; + case BRICK_SIZE_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + ( ( PMListPattern* ) child )->setBrickSize( vector ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + } + break; + } + case IMAGE_MAP_TOK: + child = new PMImageMap( m_pPart ); + error = !parseImageMap( ( PMImageMap* ) child ); + break; + case FINISH_TOK: + child = new PMFinish( m_pPart ); + error = !parseFinish( ( PMFinish* ) child ); + break; + case INTERIOR_TOK: + child = new PMInterior( m_pPart ); + error = !parseInterior( ( PMInterior* ) child ); + break; + case MEDIA_TOK: + child = new PMMedia( m_pPart ); + error = !parseMedia( ( PMMedia* ) child ); + break; + case DENSITY_TOK: + child = new PMDensity( m_pPart ); + error = !parseDensity( ( PMDensity* ) child ); + break; + case MATERIAL_TOK: + child = new PMMaterial( m_pPart ); + error = !parseMaterial( ( PMMaterial* ) child ); + break; + case SKY_SPHERE_TOK: + child = new PMSkySphere( m_pPart ); + error = !parseSkySphere( ( PMSkySphere* ) child ); + break; + case RAINBOW_TOK: + child = new PMRainbow( m_pPart ); + error = !parseRainbow( ( PMRainbow* ) child ); + break; + case FOG_TOK: + child = new PMFog( m_pPart ); + error = !parseFog( ( PMFog* ) child ); + break; + case GLOBAL_SETTINGS_TOK: + child = new PMGlobalSettings( m_pPart ); + error = !parseGlobalSettings( ( PMGlobalSettings* ) child ); + break; + case SCALE_TOK: + child = new PMScale( m_pPart ); + error = !parseScale( ( PMScale* ) child ); + break; + case ROTATE_TOK: + child = new PMRotate( m_pPart ); + error = !parseRotate( ( PMRotate* ) child ); + break; + case TRANSLATE_TOK: + child = new PMTranslate( m_pPart ); + error = !parseTranslate( ( PMTranslate* ) child ); + break; + case MATRIX_TOK: + child = new PMPovrayMatrix( m_pPart ); + error = !parseMatrix( ( PMPovrayMatrix* ) child ); + break; + case BOUNDED_BY_TOK: + if( parent && ( parent->type( ) == "ClippedBy" ) ) + finished = true; + else + { + child = new PMBoundedBy( m_pPart ); + error = !parseBoundedBy( ( PMBoundedBy* ) child ); + } + break; + case CLIPPED_BY_TOK: + if( parent && ( parent->type( ) == "BoundedBy" ) ) + finished = true; + else + { + child = new PMClippedBy( m_pPart ); + error = !parseClippedBy( ( PMClippedBy* ) child ); + } + break; + case ISOSURFACE_TOK: + child = new PMIsoSurface( m_pPart ); + error = !parseIsoSurface( ( PMIsoSurface* ) child ); + break; + case RADIOSITY_TOK: + child = new PMRadiosity( m_pPart ); + error = !parseRadiosity( ( PMRadiosity* ) child ); + break; + case PHOTONS_TOK: + if ( parent && ( parent->type( ) == "GlobalSettings" ) ) + { + child = new PMGlobalPhotons( m_pPart ); + error = !parseGlobalPhotons( ( PMGlobalPhotons* ) child ); + } + else + { + child = new PMPhotons( m_pPart ); + error =!parsePhotons( ( PMPhotons* ) child ); + } + break; + case LIGHT_GROUP_TOK: + child = new PMLightGroup( m_pPart ); + error = !parseLightGroup( ( PMLightGroup* ) child ); + break; + case INTERIOR_TEXTURE_TOK: + child = new PMInteriorTexture( m_pPart ); + error = !parseInteriorTexture( ( PMInteriorTexture* ) child ); + break; + case SPHERE_SWEEP_TOK: + child = new PMSphereSweep( m_pPart ); + error = !parseSphereSweep( ( PMSphereSweep* ) child ); + break; + case MESH_TOK: + child = new PMMesh( m_pPart ); + error = !parseMesh( ( PMMesh* ) child ); + break; + case DECLARE_TOK: + nextToken( ); + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + nextToken( ); + + if( !parseToken( '=' ) ) + error = true; + else + { + PMValue v; + switch( m_token ) + { + case OBJECT_TOK: + // finite solid + case BLOB_TOK: + case BOX_TOK: + case CONE_TOK: + case CYLINDER_TOK: + case HEIGHT_FIELD_TOK: + case JULIA_FRACTAL_TOK: + case LATHE_TOK: + case PRISM_TOK: + case SPHERE_TOK: + case SUPERELLIPSOID_TOK: + case SOR_TOK: + case TEXT_TOK: + case TORUS_TOK: + case ISOSURFACE_TOK: + case SPHERE_SWEEP_TOK: + // finite patch + case BICUBIC_PATCH_TOK: + case DISC_TOK: + case MESH_TOK: + case POLYGON_TOK: + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + // infinite solid + case PLANE_TOK: + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + // csg + case UNION_TOK: + case INTERSECTION_TOK: + case DIFFERENCE_TOK: + case MERGE_TOK: + // textures + case TEXTURE_TOK: + case INTERIOR_TEXTURE_TOK: + case PIGMENT_TOK: + case NORMAL_TOK: + case FINISH_TOK: + case TEXTURE_MAP_TOK: + case PIGMENT_MAP_TOK: + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + case NORMAL_MAP_TOK: + case SLOPE_MAP_TOK: + case DENSITY_MAP_TOK: + case INTERIOR_TOK: + case MEDIA_TOK: + case DENSITY_TOK: + case MATERIAL_TOK: + case SKY_SPHERE_TOK: + case RAINBOW_TOK: + case FOG_TOK: + // misc + case LIGHT_SOURCE_TOK: + case LIGHT_GROUP_TOK: + child = new PMDeclare( m_pPart ); + error = !parseDeclare( ( PMDeclare* ) child ); + break; + default: + // constant, vector or color declare? + if( parseNumericExpression( v ) ) + { + checkID( id, v ); + noChild = true; + } + else + error = true; + break; + } + } + + if( child ) + if( child->isA( "Declare" ) ) + ( ( PMDeclare* ) child )->setID( id ); + if( m_token == ';' ) + nextToken( ); + } + else + printExpected( i18n( "identifier" ), m_pScanner->sValue( ) ); + break; + case OBJECT_TOK: + error = !parseObject( parent ); + noChild = true; + break; + case RAW_POVRAY_TOK: + child = new PMRaw( m_pPart, m_pScanner->sValue( ) ); + error = false; + nextToken( ); + break; + default: + finished = true; + break; + } + } + if( !finished && !child && !noChild ) + error = true; + if( child ) + { + if( !insertChild( child, parent ) ) + { + delete child; + child = 0; + } + else if( child->isA( "Declare" ) ) + checkID( ( PMDeclare* ) child ); + numParsed ++; + if( ( max > 0 ) && ( numParsed >= max ) ) + finished = true; + } + } + while( !finished && !error ); + + return finished; +} + +bool PMPovrayParser::parseToken( int t, const QString& tokenName ) +{ + if( t == ',' ) + { + // do not require commas any more. + if( m_token == ',' ) + nextToken( ); + return true; + } + else if( m_token == t ) + { + nextToken( ); + return true; + } + + if( tokenName.isNull() ) + printExpected( ( char ) t, m_pScanner->sValue( ) ); + else + printExpected( tokenName, m_pScanner->sValue( ) ); + return false; +} + +bool PMPovrayParser::parseNumericItem( PMValue& v, bool checkForBool /*=false*/ ) +{ + bool finishColor = false; + PMVector cv( 0 ); + PMVector vec( 0 ); + PMValue hv; + PMSymbol* s; + int i; + + switch( m_token ) + { + case X_TOK: + v.setVector( PMVector( 1.0, 0.0, 0.0 ) ); + nextToken( ); + break; + case Y_TOK: + v.setVector( PMVector( 0.0, 1.0, 0.0 ) ); + nextToken( ); + break; + case Z_TOK: + v.setVector( PMVector( 0.0, 0.0, 1.0 ) ); + nextToken( ); + break; + case T_TOK: + v.setVector( PMVector( 0.0, 0.0, 0.0, 1.0 ) ); + nextToken( ); + break; + case U_TOK: + v.setVector( PMVector( 1.0, 0.0 ) ); + nextToken( ); + break; + case V_TOK: + v.setVector( PMVector( 0.0, 1.0 ) ); + nextToken( ); + break; + case PI_TOK: + v.setFloat( 3.1415926535897932384626 ); + nextToken( ); + break; + case CLOCK_TOK: + printMessage( PMMClockDefault ); + v.setFloat( 0.0 ); + break; + case CLOCK_DELTA_TOK: + printMessage( PMMClockDeltaDefault ); + v.setFloat( 1.0 ); + break; + case FLOAT_TOK: + v.setFloat( m_pScanner->fValue( ) ); + nextToken( ); + break; + case INTEGER_TOK: + v.setFloat( ( double ) m_pScanner->iValue( ) ); + nextToken( ); + break; + case ON_TOK: + case TRUE_TOK: + case YES_TOK: + v.setFloat( 1.0 ); + nextToken( ); + break; + case OFF_TOK: + case FALSE_TOK: + case NO_TOK: + v.setFloat( 0.0 ); + nextToken( ); + break; + case '(': + nextToken( ); + if( !parseNumericExpression( v ) ) + return false; + if( !parseToken( ')' ) ) + return false; + break; + case '-': + nextToken( ); + if( !parseNumericItem( v ) ) + return false; + if( v.type( ) == PMVFloat ) + v.setFloat( -v.floatValue( ) ); + else + v.setVector( -v.vector( ) ); + break; + case '+': + nextToken( ); + if( !parseNumericItem( v ) ) + return false; + break; + case '<': + if( !parseVectorLiteral( vec ) ) + return false; + v.setVector( vec ); + break; + case COLOR_TOK: + case COLOUR_TOK: + nextToken( ); + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + cv.resize( 5 ); + cv = 0.0; + finishColor = true; + break; + case ID_TOK: + s = getSymbol( m_pScanner->sValue( ) ); + if( s ) + { + nextToken( ); + if( s->type( ) == PMSymbol::Value ) + v = s->value( ); + else + { + printError( i18n( "Float, color or vector identifier expected." ) ); + return false; + } + } + else + { + printError( i18n( "Undefined identifier \"%1\"." ) + .arg( m_pScanner->sValue( ) ) ); + nextToken( ); + } + break; + default: + if( !checkForBool ) + printUnexpected( m_pScanner->sValue( ) ); + return false; + break; + } + + if( !finishColor ) + { + if( m_token == '.' ) + { + int index = -1; + nextToken( ); + + switch( m_token ) + { + case X_TOK: + case RED_TOK: + case U_TOK: + index = 0; + break; + case Y_TOK: + case GREEN_TOK: + case V_TOK: + index = 1; + break; + case Z_TOK: + case BLUE_TOK: + index = 2; + break; + case T_TOK: + case FILTER_TOK: + index = 3; + break; + case TRANSMIT_TOK: + index = 4; + break; + default: + break; + } + if( index >= 0 ) + { + nextToken( ); + if( v.type( ) == PMVFloat ) + { + if( index != 0 ) + index = -1; + } + else + { + PMVector vec; + if( v.type( ) == PMVVector ) + vec = v.vector( ); + else + vec = v.color( ); + + if( ( ( unsigned ) index ) < vec.size( ) ) + v.setFloat( vec[index] ); + else + index = -1; + } + } + if( index == -1 ) + { + printError( i18n( "Bad operands for period operator." ) ); + return false; + } + } + } + + while( finishColor ) + { + switch( m_token ) + { + case RGB_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 3 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBT_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + cv[4] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 4 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + cv[4] = vec[3]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBF_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv[0] = hv.floatValue( ); + cv[1] = hv.floatValue( ); + cv[2] = hv.floatValue( ); + cv[3] = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 4 ); + cv[0] = vec[0]; + cv[1] = vec[1]; + cv[2] = vec[2]; + cv[3] = vec[3]; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RGBFT_TOK: + nextToken( ); + if( !parseNumericExpression( hv ) ) + return false; + switch( hv.type( ) ) + { + case PMVFloat: + cv = hv.floatValue( ); + break; + case PMVVector: + vec = hv.vector( ); + vec.resize( 5 ); + cv = vec; + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + break; + } + break; + case RED_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[0] = hv.floatValue( ); + break; + case GREEN_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[1] = hv.floatValue( ); + break; + case BLUE_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[2] = hv.floatValue( ); + break; + case FILTER_TOK: + case ALPHA_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[3] = hv.floatValue( ); + break; + case TRANSMIT_TOK: + nextToken( ); + parseNumericExpression( hv ); + if( hv.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + break; + } + cv[4] = hv.floatValue( ); + break; + case ID_TOK: + if( parseNumericItem( hv ) ) + { + if( hv.type( ) == PMVFloat ) + { + for( i = 0; i < 5; i++ ) + cv[i] = hv.floatValue( ); + } + else if( hv.type( ) == PMVVector ) + { + cv = hv.vector( ); + cv.resize( 5 ); + } + else + cv = hv.color( ); + } + break; + default: + finishColor = false; + v.setColor( cv ); + break; + } + } + + return true; +} + +bool PMPovrayParser::parseVectorLiteral( PMVector& p ) +{ + PMValue v; + + if( !parseToken( '<' ) ) + return false; + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( 1 ); + p[0] = v.floatValue( ); + + while( m_token != '>' ) + { + // many old scenes do not use a comma between values + if( m_token == ',' ) + nextToken( ); + // parseToken( ',' ); + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( p.size( ) + 1 ); + p[p.size( ) - 1] = v.floatValue( ); + } + + /** old code + while( m_token == ',' ) + { + nextToken( ); + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) != PMVFloat ) + { + printError( i18n( "Float expression expected" ) ); + return false; + } + + p.resize( p.size( ) + 1 ); + p[p.size( ) - 1] = v.floatValue( ); + } + */ + + if( !parseToken( '>' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNumericExpression( PMValue& v, bool checkForBool /*=false*/ ) +{ + bool end = false; + PMValue v2; + PMVector hv( 0 ); + + if( !parseNumericItem( v, checkForBool ) ) + return false; + + do + { + switch( m_token ) + { + case '*': + nextToken( ); + if( !parseNumericItem( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) * v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) * v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) * v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) * v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) * v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) * v2.color( ) ); + else + printError( i18n( "You can't multiply a vector with a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) * v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) * v.color( ) ); + else + printError( i18n( "You can't multiply a vector with a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) * v2.color( ) ); + break; + } + break; + } + break; + case '/': + nextToken( ); + if( !parseNumericItem( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) / v2.floatValue( ) ); + break; + case PMVVector: + hv.resize( v2.vector( ).size( ) ); + hv = v.floatValue( ); + v.setVector( hv / v2.vector( ) ); + break; + case PMVColor: + hv.resize( 5 ); + hv = v.floatValue( ); + v.setColor( hv / v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) / v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) / v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) / v2.color( ) ); + else + printError( i18n( "You can't divide a vector by a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) / v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) / v.color( ) ); + else + printError( i18n( "You can't divide a color by a vector" ) ); + break; + case PMVColor: + v.setColor( v.color( ) / v2.color( ) ); + break; + } + break; + } + break; + case '+': + nextToken( ); + if( !parseNumericExpression( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) + v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) + v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) + v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) + v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) + v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) + v2.color( ) ); + else + printError( i18n( "You can't add a vector and a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) + v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) + v.color( ) ); + else + printError( i18n( "You can't add a vector with a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) + v2.color( ) ); + break; + } + break; + } + break; + case '-': + nextToken( ); + if( !parseNumericExpression( v2 ) ) + break; + switch( v.type( ) ) + { + case PMVFloat: + switch( v2.type( ) ) + { + case PMVFloat: + v.setFloat( v.floatValue( ) - v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v2.vector( ) - v.floatValue( ) ); + break; + case PMVColor: + v.setColor( v2.color( ) - v.floatValue( ) ); + break; + } + break; + case PMVVector: + switch( v2.type( ) ) + { + case PMVFloat: + v.setVector( v.vector( ) - v2.floatValue( ) ); + break; + case PMVVector: + v.setVector( v.vector( ) - v2.vector( ) ); + break; + case PMVColor: + if( v.vector( ).size( ) == 5 ) + v.setColor( v.vector( ) - v2.color( ) ); + else + printError( i18n( "You can't subtract a vector and a color" ) ); + break; + } + break; + case PMVColor: + switch( v2.type( ) ) + { + case PMVFloat: + v.setColor( v.color( ) - v2.floatValue( ) ); + break; + case PMVVector: + if( v2.vector( ).size( ) == 5 ) + v.setColor( v2.vector( ) - v.color( ) ); + else + printError( i18n( "You can't subtract a vector and a color" ) ); + break; + case PMVColor: + v.setColor( v.color( ) - v2.color( ) ); + break; + } + break; + } + break; + default: + end = true; + break; + } + } + while( !end ); + + return true; +} + +bool PMPovrayParser::parseVector( PMVector& vector, unsigned int size ) +{ + PMValue v; + unsigned int i; + + if( !parseNumericExpression( v ) ) + return false; + + switch( v.type( ) ) + { + case PMVFloat: + vector.resize( size ); + for( i = 0; i < size; i++ ) + vector[i] = v.floatValue( ); + break; + case PMVVector: + vector = v.vector( ); + vector.resize( size ); + break; + default: + printError( i18n( "Float or vector expression expected" ) ); + return false; + } + return true; +} + +bool PMPovrayParser::parseFloat( double& d, bool suppressError ) +{ + PMValue v; + + if( !parseNumericExpression( v, suppressError ) ) + return false; + + switch( v.type( ) ) + { + case PMVFloat: + d = v.floatValue( ); + break; + case PMVVector: + d = ( v.vector( ) )[0]; + break; + default: + printError( i18n( "Float expression expected" ) ); + return false; + } + return true; +} + +bool PMPovrayParser::parseInt( int& i ) +{ + double d; + + if( !parseFloat( d ) ) + return false; + + i = ( int ) ( d + 0.5 ); + return true; +} + +bool PMPovrayParser::parseColor( PMColor& c ) +{ + PMValue v; + + if( !parseNumericExpression( v ) ) + return false; + + if( v.type( ) == PMVColor ) + c = PMColor( v.color( ) ); + else if( v.type( ) == PMVVector ) + { + if( v.vector( ).size( ) == 5 ) + c = PMColor( v.vector( ) ); + else + { + printError( i18n( "Color expression expected" ) ); + return false; + } + } + else if( v.type( ) == PMVFloat ) + { + double d = v.floatValue( ); + c = PMColor( d, d, d, d, d ); + } + else + { + printError( i18n( "Color expression expected" ) ); + return false; + } + + return true; +} + +bool PMPovrayParser::parseObjectModifiers( PMGraphicalObject* o ) +{ + bool finished = false; + + PMSolidObject* so = 0; + if( o->isA( "SolidObject" ) ) + so = ( PMSolidObject* ) o; + + do + { + finished = true; + switch( m_token ) + { + case NO_SHADOW_TOK: + o->setNoShadow( true ); + nextToken( ); + finished = false; + break; + case NO_IMAGE_TOK: + o->setNoImage( true ); + nextToken( ); + finished = false; + break; + case NO_REFLECTION_TOK: + o->setNoReflection( true ); + nextToken( ); + finished = false; + break; + case DOUBLE_ILLUMINATE_TOK: + o->setDoubleIlluminate( true ); + nextToken( ); + finished = false; + break; + default: + break; + } + if( so ) + { + switch( m_token ) + { + case HOLLOW_TOK: + so->setHollow( PMTrue ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + so->setHollow( PMFalse ); + } + finished = false; + break; + case INVERSE_TOK: + so->setInverse( true ); + nextToken( ); + finished = false; + break; + default: + break; + } + } + } + while( !finished ); + return true; +} + +bool PMPovrayParser::parseCSG( PMCSG* pNewCSG ) +{ + int oldConsumed; + + switch( m_token ) + { + case UNION_TOK: + pNewCSG->setCSGType( PMCSG::CSGUnion ); + break; + case INTERSECTION_TOK: + pNewCSG->setCSGType( PMCSG::CSGIntersection ); + break; + case DIFFERENCE_TOK: + pNewCSG->setCSGType( PMCSG::CSGDifference ); + break; + case MERGE_TOK: + pNewCSG->setCSGType( PMCSG::CSGMerge ); + break; + default: + printUnexpected( m_pScanner->sValue( ) ); + return false; + break; + } + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCSG ); + parseObjectModifiers( pNewCSG ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBox( PMBox* pNewBox ) +{ + PMVector vector; + + int oldConsumed; + + if( !parseToken( BOX_TOK, "box" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBox->setCorner1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBox->setCorner2( vector ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBox ); + parseObjectModifiers( pNewBox ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSphere( PMSphere* pNewSphere ) +{ + PMVector vector; + double radius; + + int oldConsumed; + + if( !parseToken( SPHERE_TOK, "sphere" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewSphere->setCentre( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewSphere->setRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewSphere ); + parseObjectModifiers( pNewSphere ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCylinder( PMCylinder* pNewCyl ) +{ + PMVector vector; + double radius; + int oldConsumed; + + if( !parseToken( CYLINDER_TOK, "cylinder" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCyl->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCyl->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat(radius) ) + return false; + pNewCyl->setRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCyl ); + parseObjectModifiers( pNewCyl ); + switch( m_token ) + { + case OPEN_TOK: + nextToken( ); + pNewCyl->setOpen( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCone( PMCone* pNewCone ) +{ + PMVector vector; + double radius; + int oldConsumed; + + if( !parseToken( CONE_TOK, "cone" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewCone->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewCone->setRadius1( radius ); + + if( !parseToken( ',' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pNewCone->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewCone->setRadius2( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewCone ); + parseObjectModifiers( pNewCone ); + switch( m_token ) + { + case OPEN_TOK: + nextToken( ); + pNewCone->setOpen( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; + +} + +bool PMPovrayParser::parseTorus( PMTorus* pNewTorus ) +{ + double radius; + int oldConsumed; + + if( !parseToken( TORUS_TOK, "torus" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewTorus->setMajorRadius( radius ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( radius ) ) + return false; + pNewTorus->setMinorRadius( radius ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewTorus ); + parseObjectModifiers( pNewTorus ); + switch( m_token ) + { + case STURM_TOK: + nextToken( ); + pNewTorus->setSturm( true ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlob( PMBlob* pNewBlob ) +{ + PMVector vector; + double threshold; + int oldConsumed; + + if( !parseToken( BLOB_TOK, "blob" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + pNewBlob->setThreshold( 1.0 ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + nextToken( ); + pNewBlob->setSturm( true ); + break; + case HIERARCHY_TOK: + pNewBlob->setHierarchy( true ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewBlob->setHierarchy( false ); + } + break; + case THRESHOLD_TOK: + nextToken( ); + if( parseFloat( threshold ) ) + { + if( threshold <= 0 ) + printError( i18n( "The threshold value has to be positive" ) ); + else + pNewBlob->setThreshold( threshold ); + } + break; + } + + parseChildObjects( pNewBlob ); + parseObjectModifiers( pNewBlob ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlobSphere( PMBlobSphere* pNewBlobSphere ) +{ + PMVector vector; + double radius; + double strength; + + int oldConsumed; + + if( !parseToken( SPHERE_TOK, "sphere" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobSphere->setCentre( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobSphere->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( m_token == STRENGTH_TOK ) + nextToken( ); + + if( !parseFloat( strength ) ) + return false; + pNewBlobSphere->setStrength( strength ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBlobSphere ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBlobComponent( PMBlobSphere* pNewBlobSphere ) +{ + PMVector vector; + double radius; + double strength; + + if( !parseToken( COMPONENT_TOK, "component" ) ) + return false; + + if( !parseFloat( strength ) ) + return false; + pNewBlobSphere->setStrength( strength ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobSphere->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobSphere->setCentre( vector ); + + return true; +} + +bool PMPovrayParser::parseBlobCylinder( PMBlobCylinder* pNewBlobCylinder ) +{ + PMVector vector; + double radius; + double strength; + int oldConsumed; + + if( !parseToken( CYLINDER_TOK, "cylinder" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobCylinder->setEnd1( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewBlobCylinder->setEnd2( vector ); + + if( !parseToken( ',' ) ) + return false; + + if( !parseFloat( radius ) ) + return false; + pNewBlobCylinder->setRadius( radius ); + + if( !parseToken( ',' ) ) + return false; + + if( m_token == STRENGTH_TOK ) + nextToken( ); + + if( !parseFloat( strength ) ) + return false; + pNewBlobCylinder->setStrength( strength ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewBlobCylinder ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseHeightField( PMHeightField* pNewHeightField ) +{ + int oldConsumed; + double wl; + + if( !parseToken( HEIGHT_FIELD_TOK, "height_field" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + switch( m_token ) + { + case GIF_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFgif ); + nextToken( ); + break; + case TGA_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFtga ); + nextToken( ); + break; + case POT_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpot ); + nextToken( ); + break; + case PNG_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpng ); + nextToken( ); + break; + case PGM_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFpgm ); + nextToken( ); + break; + case PPM_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFppm ); + nextToken( ); + break; + case SYS_TOK: + pNewHeightField->setHeightFieldType( PMHeightField::HFsys ); + nextToken( ); + break; + default: + printExpected( i18n( "height field type" ), m_pScanner->sValue( ) ); + return false; + } + if( m_token != STRING_TOK ) + { + printExpected( i18n( "height field file" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewHeightField->setFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case SMOOTH_TOK: + nextToken( ); + pNewHeightField->setSmooth( true ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewHeightField->setSmooth( false ); + } + break; + case HIERARCHY_TOK: + pNewHeightField->setHierarchy( true ); + nextToken( ); + if( isTrue( ) ) + nextToken( ); + else if( isFalse( ) ) + { + nextToken( ); + pNewHeightField->setHierarchy( false ); + } + break; + case WATER_LEVEL_TOK: + nextToken( ); + if( parseFloat( wl ) ) + { + if( ( wl < 0.0 ) || ( wl > 1.0 ) ) + printError( i18n( "The water level has to be between 0 and 1" ) ); + else + pNewHeightField->setWaterLevel( wl ); + } + break; + } + + parseChildObjects( pNewHeightField ); + parseObjectModifiers( pNewHeightField ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseText( PMText* pNewText ) +{ + int oldConsumed; + double thickness; + PMVector offset; + + if( !parseToken( TEXT_TOK, "text" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseToken( TTF_TOK, "ttf" ) ) + return false; + + if( m_token != STRING_TOK ) + { + printExpected( i18n( "font file name" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewText->setFont( m_pScanner->sValue( ) ); + nextToken( ); + } + if( m_token != STRING_TOK ) + { + printExpected( i18n( "string of text" ), m_pScanner->sValue( ) ); + return false; + } + else + { + pNewText->setText( m_pScanner->sValue( ) ); + nextToken( ); + } + + if( !parseFloat( thickness ) ) + return false; + pNewText->setThickness( thickness ); + + parseToken( ',' ); + + if( parseVector( offset, 2 ) ) + pNewText->setOffset( offset ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewText ); + parseObjectModifiers( pNewText ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseJuliaFractal( PMJuliaFractal* pNewFractal ) +{ + int oldConsumed; + double d; + int i; + PMVector v( 4 ), v2( 2 ); + + if( !parseToken( JULIA_FRACTAL_TOK, "julia_fractal" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( v, 4 ) ) + return false; + pNewFractal->setJuliaParameter( v ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case QUATERNION_TOK: + pNewFractal->setAlgebraType( PMJuliaFractal::Quaternion ); + nextToken( ); + break; + case HYPERCOMPLEX_TOK: + pNewFractal->setAlgebraType( PMJuliaFractal::Hypercomplex ); + nextToken( ); + break; + case SQR_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsqr ); + nextToken( ); + break; + case CUBE_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcube ); + nextToken( ); + break; + case EXP_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTexp ); + nextToken( ); + break; + case RECIPROCAL_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTreciprocal ); + nextToken( ); + break; + case SIN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsin ); + nextToken( ); + break; + case ASIN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTasin ); + nextToken( ); + break; + case SINH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTsinh ); + nextToken( ); + break; + case ASINH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTasinh ); + nextToken( ); + break; + case COS_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcos ); + nextToken( ); + break; + case ACOS_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTacos ); + nextToken( ); + break; + case COSH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTcosh ); + nextToken( ); + break; + case ACOSH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTacosh ); + nextToken( ); + break; + case TAN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTtan ); + nextToken( ); + break; + case ATAN_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTatan ); + nextToken( ); + break; + case TANH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTtanh ); + nextToken( ); + break; + case ATANH_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTatanh ); + nextToken( ); + break; + case LOG_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTlog ); + nextToken( ); + break; + case PWR_TOK: + pNewFractal->setFunctionType( PMJuliaFractal::FTpwr ); + nextToken( ); + if( !parseToken( '(' ) ) + return false; + if( !parseFloat( v2[0] ) ) + return false; + parseToken( ',' ); + if( !parseFloat( v2[1] ) ) + return false; + if( !parseToken( ')' ) ) + return false; + pNewFractal->setExponent( v2 ); + break; + case MAX_ITERATION_TOK: + nextToken( ); + if( !parseInt( i ) ) + return false; + if( i <= 0 ) + { + printWarning( i18n( "Maximum iterations are less than 1, fixed" ) ); + i = 1; + } + pNewFractal->setMaximumIterations( i ); + break; + case PRECISION_TOK: + nextToken( ); + if( !parseFloat( d ) ) + return false; + if( d < 1.0 ) + { + printWarning( i18n( "Precision is less than 1.0, fixed" ) ); + d = 1.0; + } + pNewFractal->setPrecision( d ); + break; + case SLICE_TOK: + nextToken( ); + if( !parseVector( v, 4 ) ) + return false; + pNewFractal->setSliceNormal( v ); + parseToken( ',' ); + if( !parseFloat( d ) ) + return false; + pNewFractal->setSliceDistance( d ); + break; + } + + parseChildObjects( pNewFractal ); + parseObjectModifiers( pNewFractal ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePlane( PMPlane* pNewPlane ) +{ + double dist; + PMVector vector; + int oldConsumed; + + if( !parseToken( PLANE_TOK, "plane" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewPlane->setNormal( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( dist ) ) + return false; + pNewPlane->setDistance( dist ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewPlane ); + parseObjectModifiers( pNewPlane ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +const int c_polynomSize[8] = { 0, 0, 10, 20, 35, 56, 84, 120 }; + +bool PMPovrayParser::parsePolynom( PMPolynom* pNewPoly ) +{ + PMVector vector; + double d; + PMVector c; + int oldConsumed; + int order = 2; + int type = m_token; + + pNewPoly->setSturm( false ); + + if( ( m_token == QUADRIC_TOK ) || ( m_token == CUBIC_TOK ) || + ( m_token == QUARTIC_TOK ) || ( m_token == POLY_TOK ) ) + { + nextToken( ); + if( !parseToken( '{' ) ) + return false; + } + else + printExpected( "poly", m_pScanner->sValue( ) ); + + if( type == QUADRIC_TOK ) + { + c = PMVector( 10 ); + pNewPoly->setPolynomOrder( 2 ); + + // parse the quadric coefficients + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[0] = vector[0]; + c[4] = vector[1]; + c[7] = vector[2]; + parseToken( ',' ); + + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[1] = vector[0]; + c[2] = vector[1]; + c[5] = vector[2]; + parseToken( ',' ); + + if( !parseVectorLiteral( vector ) ) + return false; + vector.resize( 3 ); + c[3] = vector[0]; + c[6] = vector[1]; + c[8] = vector[2]; + parseToken( ',' ); + + if( !parseFloat( d ) ) + return false; + c[9] = d; + + pNewPoly->setCoefficients( c ); + } + else + { + if( type == CUBIC_TOK ) + order = 3; + else if( type == QUARTIC_TOK ) + order = 4; + else + { + if( !parseInt( order ) ) + return false; + if( ( order < 2 ) || ( order > 7 ) ) + { + printError( i18n( "The polynom order has to be between 2 and 7 inclusive" ) ); + return false; + } + parseToken( ',' ); + } + + pNewPoly->setPolynomOrder( order ); + + if( !parseVectorLiteral( vector ) ) + return false; + + if( vector.size( ) != ( unsigned ) c_polynomSize[order] ) + { + printError( i18n( "%1 coefficients are needed for a polynom with order %2" ) + .arg( c_polynomSize[order] ).arg( order ) ); + vector.resize( c_polynomSize[order] ); + } + pNewPoly->setCoefficients( vector ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == STURM_TOK ) + { + pNewPoly->setSturm( true ); + nextToken( ); + } + + parseChildObjects( pNewPoly ); + parseObjectModifiers( pNewPoly ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBicubicPatch( PMBicubicPatch* pNewPatch ) +{ + PMVector vector; + bool stop = false; + int oldConsumed; + int type; + int steps; + double flatness; + int i; + + if( !parseToken( BICUBIC_PATCH_TOK, "bicubic_patch" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + // parse patch items + do + { + switch( m_token ) + { + case TYPE_TOK: + nextToken( ); + if( parseInt( type ) ) + { + if( ( type == 0 ) || ( type == 1 ) ) + pNewPatch->setPatchType( type ); + else + printError( i18n( "Patch type has to be 0 or 1" ) ); + } + break; + case U_STEPS_TOK: + nextToken( ); + if( parseInt( steps ) ) + pNewPatch->setUSteps( steps ); + break; + case V_STEPS_TOK: + nextToken( ); + if( parseInt( steps ) ) + pNewPatch->setVSteps( steps ); + break; + case FLATNESS_TOK: + nextToken( ); + if( parseFloat( flatness ) ) + pNewPatch->setFlatness( flatness ); + break; + case UV_VECTORS_TOK: + pNewPatch->enableUV( true ); + nextToken( ); + for ( i = 0; i < 4; ++i ) + { + if( parseVector( vector ) ) + pNewPatch->setUVVector( i, vector ); + else + return false; + } + break; + case ',': + nextToken( ); + stop = true; + break; + default: + stop = true; + break; + } + } + while( !stop ); + + // parse control points + stop = false; + for( i = 0; ( i < 16 ) && !stop; i++ ) + { + if( parseVector( vector ) ) + { + pNewPatch->setControlPoint( i, vector ); + if( i < 15 ) + if( !parseToken( ',' ) ) + stop = true; + } + else + stop = true; + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewPatch ); + parseObjectModifiers( pNewPatch ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDisc( PMDisc* pNewDisc ) +{ + double d; + PMVector vector; + int oldConsumed; + + if( !parseToken( DISC_TOK, "disc" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + pNewDisc->setCenter( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pNewDisc->setNormal( vector ); + + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( d ) ) + return false; + pNewDisc->setRadius( d ); + + if( m_token == ',' ) + { + nextToken( ); + if( !parseFloat( d ) ) + return false; + pNewDisc->setHoleRadius( d ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewDisc ); + parseObjectModifiers( pNewDisc ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseTriangle( PMTriangle* pNewTriangle ) +{ + PMVector vector; + int oldConsumed; + int i; + + if( m_token == SMOOTH_TRIANGLE_TOK ) + pNewTriangle->setSmoothTriangle( true ); + else if( m_token == TRIANGLE_TOK ) + pNewTriangle->setSmoothTriangle( false ); + else + { + printExpected( "triangle", m_pScanner->sValue( ) ); + return false; + } + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + for( i = 0; i < 3; i++ ) + { + if( i != 0 ) + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + pNewTriangle->setPoint( i, vector ); + + if( pNewTriangle->isSmoothTriangle( ) ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + pNewTriangle->setNormal( i, vector ); + } + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewTriangle ); + parseObjectModifiers( pNewTriangle ); + if( m_token == UV_VECTORS_TOK ) + { + nextToken( ); + pNewTriangle->enableUV( true ); + for ( i = 0; i < 3; ++i ) + { + if( parseVector( vector ) ) + pNewTriangle->setUVVector( i, vector ); + else + return false; + } + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLathe( PMLathe* pNewLathe ) +{ + PMVector vector; + int oldConsumed; + int i; + bool stop = false; + + if( !parseToken( LATHE_TOK, "lathe" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int minp = 2; + while( !stop ) + { + switch( m_token ) + { + case LINEAR_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::LinearSpline ); + nextToken( ); + minp = 2; + break; + case QUADRATIC_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::QuadraticSpline ); + nextToken( ); + minp = 3; + break; + case CUBIC_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::CubicSpline ); + nextToken( ); + minp = 4; + break; + case BEZIER_SPLINE_TOK: + pNewLathe->setSplineType( PMLathe::BezierSpline ); + nextToken( ); + minp = 4; + break; + default: + stop = true; + break; + } + } + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList<PMVector> points; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + points.append( vector ); + } + + if( nump < minp ) + printError( i18n( "At least %1 points are needed for that spline type" ) + .arg( minp ) ); + else if( ( pNewLathe->splineType( ) == PMLathe::BezierSpline ) && + ( ( nump % 4 ) != 0 ) ) + printError( i18n( "Bezier splines need 4 points for each segment" ) ); + else + pNewLathe->setPoints( points ); + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == STURM_TOK ) + { + pNewLathe->setSturm( true ); + nextToken( ); + } + + parseChildObjects( pNewLathe ); + parseObjectModifiers( pNewLathe ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePrism( PMPrism* pNewPrism ) +{ + PMVector vector; + double height; + int oldConsumed; + int i; + bool stop = false; + + if( !parseToken( PRISM_TOK, "prism" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int minp = 3; + while( !stop ) + { + switch( m_token ) + { + case LINEAR_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::LinearSpline ); + nextToken( ); + minp = 3; + break; + case QUADRATIC_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::QuadraticSpline ); + nextToken( ); + minp = 4; + break; + case CUBIC_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::CubicSpline ); + nextToken( ); + minp = 5; + break; + case BEZIER_SPLINE_TOK: + pNewPrism->setSplineType( PMPrism::BezierSpline ); + nextToken( ); + minp = 4; + break; + case LINEAR_SWEEP_TOK: + pNewPrism->setSweepType( PMPrism::LinearSweep ); + nextToken( ); + break; + case CONIC_SWEEP_TOK: + pNewPrism->setSweepType( PMPrism::ConicSweep ); + nextToken( ); + break; + default: + stop = true; + break; + } + } + + if( !parseFloat( height ) ) + return false; + pNewPrism->setHeight1( height ); + parseToken( ',' ); + if( !parseFloat( height ) ) + return false; + pNewPrism->setHeight2( height ); + parseToken( ',' ); + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList<PMVector> allPoints; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + allPoints.append( vector ); + } + + QValueList< QValueList<PMVector> > points; + QValueList<PMVector> subPoints; + QValueList<PMVector>::Iterator it = allPoints.begin( ); + int pnr = 0, pmod4; + PMVector ref( 2 ), ref2( 2 ); + bool error = false; + bool last = false; + + switch( pNewPrism->splineType( ) ) + { + case PMPrism::LinearSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + { + ref = *it; + subPoints.append( *it ); + } + else + { + if( ref.approxEqual( *it ) ) + { + if( pnr < 3 ) + { + printError( i18n( "Linear splines need at least 4 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + } + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printWarning( i18n( "Linear spline not closed" ) ); + if( pnr < 3 ) + { + printError( i18n( "Linear splines need at least 4 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + } + } + break; + case PMPrism::QuadraticSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + subPoints.append( *it ); + else if( pnr == 1 ) + { + ref = *it; + subPoints.append( *it ); + } + else + { + if( ref.approxEqual( *it ) ) + { + if( pnr < 4 ) + { + printError( i18n( "Quadratic splines need at least 5 points." ) ); + error = true; + } + else + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + } + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Quadratic spline not closed" ) ); + error = true; + } + break; + case PMPrism::CubicSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + if( pnr == 0 ) + subPoints.append( *it ); + else if( pnr == 1 ) + { + ref = *it; + subPoints.append( *it ); + } + else if( last ) + { + if( pnr < 5 ) + { + printError( i18n( "Cubic splines need at least 6 points." ) ); + error = true; + } + else + { + subPoints.append( *it ); + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + last = false; + } + } + else + { + if( ref.approxEqual( *it ) ) + last = true; + else + subPoints.append( *it ); + } + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Cubic spline not closed" ) ); + error = true; + } + break; + case PMPrism::BezierSpline: + for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ ) + { + pmod4 = pnr % 4; + + if( pnr == 0 ) + { + ref = *it; + subPoints.append( *it ); + } + else if( pmod4 == 0 ) + { + if( !ref2.approxEqual( *it ) ) + { + printError( i18n( "Bezier spline not closed" ) ); + error = true; + } + } + else if( pmod4 == 3 ) + { + if( ref.approxEqual( *it ) ) + { + points.append( subPoints ); + subPoints.clear( ); + pnr = -1; + } + else + { + subPoints.append( *it ); + ref2 = *it; + } + } + else + subPoints.append( *it ); + } + if( ( pnr != 0 ) && ( !error ) ) + { + printError( i18n( "Bezier spline not closed" ) ); + error = true; + } + break; + } + + if( !error ) + pNewPrism->setPoints( points ); + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + pNewPrism->setSturm( true ); + nextToken( ); + break; + case OPEN_TOK: + pNewPrism->setOpen( true ); + nextToken( ); + break; + default: + break; + } + + parseChildObjects( pNewPrism ); + parseObjectModifiers( pNewPrism ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSor( PMSurfaceOfRevolution* pNewSor ) +{ + PMVector vector; + int oldConsumed; + int i; + + if( !parseToken( SOR_TOK, "sor" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + int nump; + if( !parseInt( nump ) ) + return false; + + QValueList<PMVector> points; + for( i = 0; i < nump; i++ ) + { + parseToken( ',' ); + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + points.append( vector ); + } + + if( nump < 4 ) + printError( i18n( "At least 4 points are needed for the surface of revolution" ) ); + else + { + QValueList<PMVector>::Iterator it1 = points.begin( ); + QValueList<PMVector>::Iterator it2 = it1; ++it2; + QValueList<PMVector>::Iterator it3 = it2; ++it3; + int pnr = 0; + + for( ; it3 != points.end( ); ++it1, ++it2, ++it3, pnr++ ) + { + if( ( pnr == 0 ) || ( pnr == ( nump - 3 ) ) ) + { + if( approxZero( ( *it1 )[1] - ( *it3 )[1], c_sorTolerance ) ) + { + printError( i18n( "The v coordinate of point %1 and %2 must be different; fixed" ) + .arg( pnr + 1 ).arg( pnr + 3 ) ); + if( pnr == 0 ) + ( *it1 )[1] = ( *it3 )[1] - c_sorTolerance; + else + ( *it3 )[1] = ( *it1 )[1] + c_sorTolerance; + } + } + + if( pnr != 0 ) + { + if( ( ( *it2 )[1] - ( *it1 )[1] ) < c_sorTolerance ) + { + printError( i18n( "The v coordinates must be strictly increasing; fixed" ) ); + ( *it2 )[1] = ( *it1 )[1] + c_sorTolerance; + } + } + } + pNewSor->setPoints( points ); + } + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case STURM_TOK: + pNewSor->setSturm( true ); + nextToken( ); + break; + case OPEN_TOK: + pNewSor->setOpen( true ); + nextToken( ); + break; + default: + break; + } + + parseChildObjects( pNewSor ); + parseObjectModifiers( pNewSor ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSqe( PMSuperquadricEllipsoid* pNewSqe ) +{ + PMVector vector; + int oldConsumed; + + if( !parseToken( SUPERELLIPSOID_TOK ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( !parseVector( vector ) ) + return false; + vector.resize( 2 ); + + if( vector[0] < 0.001 ) + { + printError( i18n( "The east-west exponent must be greater than 0.001" ) ); + vector[0] = 0.001; + } + if( vector[1] < 0.001 ) + { + printError( i18n( "The north-south exponent must be greater than 0.001" ) ); + vector[1] = 0.001; + } + + pNewSqe->setEastWestExponent( vector[0] ); + pNewSqe->setNorthSouthExponent( vector[1] ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pNewSqe ); + parseObjectModifiers( pNewSqe ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRotate( PMRotate* rotate ) +{ + PMVector v; + + if( !parseToken( ROTATE_TOK, "rotate" ) ) + return false; + if( !parseVector( v ) ) + return false; + + rotate->setRotation( v ); + return true; +} + +bool PMPovrayParser::parseScale( PMScale* scale ) +{ + PMVector v; + + if( !parseToken( SCALE_TOK, "scale" ) ) + return false; + if( !parseVector( v ) ) + return false; + + scale->setScale( v ); + return true; +} + +bool PMPovrayParser::parseTranslate( PMTranslate* translate ) +{ + PMVector v; + + if( !parseToken( TRANSLATE_TOK, "translate" ) ) + return false; + if( !parseVector( v ) ) + return false; + + translate->setTranslation( v ); + return true; +} + +bool PMPovrayParser::parseMatrix( PMPovrayMatrix* matrix ) +{ + PMVector v; + + if( !parseToken( MATRIX_TOK ), "matrix" ) + return false; + if( !parseVectorLiteral( v ) ) + return false; + + if( v.size( ) != 12 ) + { + printError( i18n( "Wrong number of matrix values." ) ); + v.resize( 12 ); + } + matrix->setValues( v ); + return true; +} + +bool PMPovrayParser::parseBoundedBy( PMBoundedBy* bound ) +{ + int oldConsumed; + + if( !parseToken( BOUNDED_BY_TOK, "bounded_by" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == CLIPPED_BY_TOK ) + nextToken( ); + + parseChildObjects( bound ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseClippedBy( PMClippedBy* clipped ) +{ + int oldConsumed; + + if( !parseToken( CLIPPED_BY_TOK, "clipped_by" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == BOUNDED_BY_TOK ) + nextToken( ); + + parseChildObjects( clipped ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseCamera( PMCamera* camera ) +{ + PMVector v; + double d; + int i; + + int oldConsumed; + + if( !parseToken( CAMERA_TOK, "camera" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + + do + { + oldConsumed = m_consumedTokens; + + switch( m_token ) + { + case PERSPECTIVE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Perspective ); + break; + case ORTHOGRAPHIC_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Orthographic ); + break; + case FISHEYE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::FishEye ); + break; + case ULTRA_WIDE_ANGLE_TOK: + nextToken( ); + camera->setCameraType( PMCamera::UltraWideAngle ); + break; + case OMNIMAX_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Omnimax ); + break; + case PANORAMIC_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Panoramic ); + break; + case CYLINDER_TOK: + nextToken( ); + camera->setCameraType( PMCamera::Cylinder ); + if( parseInt( i ) ) + camera->setCylinderType( i ); + break; + case LOCATION_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setLocation( v ); + break; + case SKY_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setSky( v ); + break; + case UP_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setUp( v ); + break; + case RIGHT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setRight( v ); + break; + case DIRECTION_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setDirection( v ); + break; + case LOOK_AT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setLookAt( v ); + break; + case ANGLE_TOK: + nextToken( ); + if( parseFloat( d ) ) + { + camera->enableAngle( true ); + camera->setAngle( d ); + } + break; + case BLUR_SAMPLES_TOK: + nextToken( ); + camera->enableFocalBlur( true ); + if( parseInt( i ) ) + camera->setBlurSamples( i ); + break; + case APERTURE_TOK: + nextToken( ); + camera->enableFocalBlur( true ); + if( parseFloat( d ) ) + camera->setAperture( d ); + break; + case FOCAL_POINT_TOK: + nextToken( ); + if( parseVector( v ) ) + camera->setFocalPoint( v ); + break; + case CONFIDENCE_TOK: + nextToken( ); + if( parseFloat( d ) ) + camera->setConfidence( d ); + break; + case VARIANCE_TOK: + nextToken( ); + if( parseFloat( d ) ) + camera->setVariance( d ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + parseChildObjects( camera ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLight( PMLight* light ) +{ + PMVector v; + PMColor c; + double d; + int i; + + int oldConsumed; + + if( !parseToken( LIGHT_SOURCE_TOK, "light_source" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + if( !parseVector( v ) ) + return false; + light->setLocation( v ); + if( m_token == ',' ) + nextToken( ); + if( !parseColor( c ) ) + return false; + light->setColor( c ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( light ); + + switch( m_token ) + { + case SPOTLIGHT_TOK: + nextToken( ); + light->setLightType( PMLight::SpotLight ); + break; + case CYLINDER_TOK: + nextToken( ); + light->setLightType( PMLight::CylinderLight ); + break; + case SHADOWLESS_TOK: + nextToken( ); + light->setLightType( PMLight::ShadowlessLight ); + break; + case RADIUS_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setRadius( d ); + break; + case FALLOFF_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setFalloff( d ); + break; + case TIGHTNESS_TOK: + nextToken( ); + if( parseFloat( d ) ) + light->setTightness( d ); + break; + case POINT_AT_TOK: + nextToken( ); + if( parseVector( v ) ) + light->setPointAt( v ); + break; + case PARALLEL_TOK: + nextToken( ); + light->setParallel( parseBool( ) ); + break; + case AREA_LIGHT_TOK: + nextToken( ); + light->setAreaLight( true ); + if( parseVector( v ) ) + light->setAxis1( v ); + parseToken( ',' ); + if( parseVector( v ) ) + light->setAxis2( v ); + parseToken( ',' ); + if( parseInt( i ) ) + light->setSize1( i ); + parseToken( ',' ); + if( parseInt( i ) ) + light->setSize2( i ); + break; + case AREA_CIRCULAR_TOK: + nextToken( ); + light->setAreaType( PMLight::Circular ); + break; + case ADAPTIVE_TOK: + nextToken( ); + if( parseInt( i ) ) + light->setAdaptive( i ); + break; + case ORIENT_TOK: + nextToken( ); + light->setOrient( parseBool( ) ); + break; + case JITTER_TOK: + nextToken( ); + light->setJitter( parseBool( ) ); + break; + case FADE_POWER_TOK: + nextToken( ); + light->setFading( true ); + if( parseInt( i ) ) + light->setFadePower( i ); + break; + case FADE_DISTANCE_TOK: + nextToken( ); + light->setFading( true ); + if( parseFloat( d ) ) + light->setFadeDistance( d ); + break; + case MEDIA_INTERACTION_TOK: + nextToken( ); + light->setMediaInteraction( parseBool( ) ); + break; + case MEDIA_ATTENUATION_TOK: + nextToken( ); + light->setMediaAttenuation( parseBool( ) ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLooksLike( PMLooksLike* ll ) +{ + if( !parseToken( LOOKS_LIKE_TOK, "looks_like" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + parseChildObjects( ll ); + + if( !parseToken( '}' ) ) + return false; + return true; +} + +bool PMPovrayParser::parseProjectedThrough( PMProjectedThrough* ll ) +{ + if( !parseToken( PROJECTED_THROUGH_TOK, "projected_through" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + parseChildObjects( ll ); + + if( !parseToken( '}' ) ) + return false; + return true; +} + +bool PMPovrayParser::parseTexture( PMTexture* texture, bool parseOuter ) +{ + int oldConsumed; + + if( parseOuter ) + { + if( !parseToken( TEXTURE_TOK, "texture" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + } + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !texture->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( texture ); + if( m_token == UV_MAPPING_TOK ) + { + nextToken(); + texture->setUVMapping( parseBool( ) ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( parseOuter ) + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePattern( PMPattern* pattern, bool normal ) +{ + PMVector vector; + double f_number; + int i_number; + int oldConsumed; + bool type; + + do + { + oldConsumed = m_consumedTokens; + type = false; + + switch( m_token ) + { + case AGATE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternAgate ); + type = true; + break; + case AGATE_TURB_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setAgateTurbulence( f_number ); + break; + case AVERAGE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternAverage ); + type = true; + break; + case BOXED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBoxed ); + type = true; + break; + case BOZO_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBozo ); + type = true; + break; + case BUMPS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternBumps ); + type = true; + break; + case CELLS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCells ); + type = true; + break; + case CRACKLE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCrackle ); + type = true; + break; + case CYLINDRICAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternCylindrical ); + type = true; + break; + case DENTS_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternDents ); + type = true; + break; + case DENSITY_FILE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternDensity ); + type = true; + if( !parseToken( DF3_TOK, "df3" ) ) + return false; + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + pattern->setDensityFile( m_pScanner->sValue( ) ); + nextToken( ); + } + if( parseToken( INTERPOLATE_TOK, "interpolate" ) ) + { + if( !parseInt( i_number ) ) + return false; + else + pattern->setDensityInterpolate( i_number ); + } + break; + case GRADIENT_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternGradient ); + type = true; + if( !parseVector( vector ) ) + return false; + pattern->setGradient( vector ); + break; + case GRANITE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternGranite ); + type = true; + break; + case JULIA_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternJulia ); + type = true; + if( !parseVector( vector ) ) + return false; + pattern->setJuliaComplex( vector ); + if( !parseInt( i_number ) ) + return false; + pattern->setMaxIterations( i_number ); + break; + case LEOPARD_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternLeopard ); + type = true; + break; + case MANDEL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternMandel ); + type = true; + if( !parseInt( i_number ) ) + return false; + pattern->setMaxIterations( i_number ); + break; + case MARBLE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternMarble ); + type = true; + break; + case ONION_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternOnion ); + type = true; + break; + case PLANAR_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternPlanar ); + type = true; + break; + case QUILTED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternQuilted ); + type = true; + break; + case CONTROL0_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setQuiltControl0( f_number ); + break; + case CONTROL1_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setQuiltControl1( f_number ); + break; + case RADIAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternRadial ); + type = true; + break; + case RIPPLES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternRipples ); + type = true; + break; + case SLOPE_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSlope ); + type = true; + if( !parseToken( '{' ) ) + return false; + if( !parseVector( vector ) ) + return false; + pattern->setSlopeDirection( vector ); + if ( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + pattern->setSlopeLoSlope( f_number ); + if ( parseToken( ',' ) ) + { + if ( !parseFloat( f_number ) ) + return false; + pattern->setSlopeHiSlope( f_number ); + } + } + if( m_token == ALTITUDE_TOK ) + { + pattern->setSlopeAltFlag( true ); + nextToken( ); + if ( !parseVector( vector ) ) + return false; + pattern->setSlopeAltitude( vector ); + if( parseToken( ',' ) ) + { + if ( !parseFloat( f_number ) ) + return false; + pattern->setSlopeLoAlt( f_number ); + if ( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + pattern->setSlopeHiAlt( f_number ); + } + } + } + if( !parseToken( '}' ) ) + return false; + break; + case SPHERICAL_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSpherical ); + type = true; + break; + case SPIRAL1_TOK: + case SPIRAL2_TOK: + if( m_token == SPIRAL1_TOK ) + pattern->setPatternType( PMPattern::PatternSpiral1 ); + else + pattern->setPatternType( PMPattern::PatternSpiral2 ); + type = true; + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setSpiralNumberArms( i_number ); + break; + case SPOTTED_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternSpotted ); + type = true; + break; + case WAVES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWaves ); + type = true; + break; + case WOOD_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWood ); + type = true; + break; + case WRINKLES_TOK: + nextToken( ); + pattern->setPatternType( PMPattern::PatternWrinkles ); + type = true; + break; + + //crackle parameters + case FORM_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + pattern->setCrackleForm( vector ); + break; + case METRIC_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setCrackleMetric( i_number ); + break; + case OFFSET_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setCrackleOffset( f_number ); + break; + case SOLID_TOK: + nextToken( ); + pattern->setCrackleSolid( true ); + break; + + //fractal parameters + case MAGNET_TOK: + nextToken( ); + pattern->setFractalMagnet( true ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalMagnetType( i_number ); + break; + case EXPONENT_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalExponent( i_number ); + break; + case EXTERIOR_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalExtType( i_number ); + if ( !parseFloat( f_number ) ) + return false; + pattern->setFractalExtFactor( f_number ); + break; + case INTERIOR_TOK: + nextToken( ); + if ( !parseInt( i_number ) ) + return false; + pattern->setFractalIntType( i_number ); + if ( !parseFloat( f_number ) ) + return false; + pattern->setFractalIntFactor( f_number ); + break; + + //turbulence + case TURBULENCE_TOK: + nextToken( ); + pattern->enableTurbulence( true ); + if( !parseVector( vector ) ) + return false; + pattern->setValueVector( vector ); + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + pattern->setLambda( f_number ); + break; + + case NOISE_GENERATOR_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + pattern->setNoiseGenerator( ( PMPattern::PMNoiseType ) ( i_number ) ); + break; + default: + break; + } + + if( type && normal ) + { + // try to parse the normal pattern depth + double depth; + if( parseFloat( depth, true ) ) + pattern->setDepth( depth ); + } + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseBlendMapModifiers( PMBlendMapModifiers* blend ) +{ + int oldConsumed; + double f_number; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case FREQUENCY_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + blend->enableFrequency( true ); + blend->setFrequency( f_number ); + break; + case PHASE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + blend->enablePhase( true ); + blend->setPhase( f_number ); + break; + case RAMP_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::RampWave ); + break; + case TRIANGLE_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::TriangleWave ); + break; + case SINE_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::SineWave ); + break; + case SCALLOP_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::ScallopWave ); + break; + case CUBIC_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::CubicWave ); + break; + case POLY_WAVE_TOK: + nextToken( ); + blend->enableWaveForm( true ); + blend->setWaveFormType( PMBlendMapModifiers::PolyWave ); + if( parseFloat( f_number, true ) ) + blend->setWaveFormExponent( f_number ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseWarp( PMWarp* warp ) +{ + int oldConsumed; + PMVector vector; + double f_number; + int i_number; + bool parsedFirst; + bool mapping; + + if( !parseToken( WARP_TOK, "warp" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + mapping = false; + parsedFirst = false; + do + { + oldConsumed = m_consumedTokens; + if( !parsedFirst && + ( m_token != REPEAT_TOK || + m_token != BLACK_HOLE_TOK || + m_token != TURBULENCE_TOK || + m_token != CYLINDRICAL_TOK || + m_token != SPHERICAL_TOK || + m_token != TOROIDAL_TOK || + m_token != PLANAR_TOK ) ) + { + printError( i18n( "Expecting a warp type" ) ); + return false; + } + switch( m_token ) + { + case REPEAT_TOK: + nextToken( ); + if( !parsedFirst ) + { + warp->setWarpType( PMWarp::Repeat ); + if( !parseVector( vector ) ) + return false; + warp->setDirection( vector ); + parsedFirst = true; + } + else + { + if( !parseVector( vector ) ) + return false; + warp->setRepeat( vector ); + } + break; + case OFFSET_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setOffset( vector ); + break; + case FLIP_TOK: + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setFlip( vector ); + break; + case BLACK_HOLE_TOK: + nextToken( ); + warp->setWarpType( PMWarp::BlackHole ); + if( !parseVector( vector ) ) + return false; + warp->setLocation( vector ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + warp->setRadius( f_number ); + parsedFirst = true; + break; + case STRENGTH_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setStrength( f_number ); + break; + case FALLOFF_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setFalloff( f_number ); + break; + case INVERSE_TOK: + nextToken( ); + warp->setInverse( true ); + break; + case TURBULENCE_TOK: + if( !parsedFirst ) + { + nextToken( ); + warp->setWarpType( PMWarp::Turbulence ); + if( !parseVector( vector ) ) + return false; + warp->setValueVector( vector ); + parsedFirst = true; + } + else + { + if( !parseVector( vector ) ) + return false; + warp->setTurbulence( vector ); + } + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + warp->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setLambda( f_number ); + break; + case CYLINDRICAL_TOK: + warp->setWarpType( PMWarp::Cylindrical ); + mapping = true; + break; + case SPHERICAL_TOK: + warp->setWarpType( PMWarp::Spherical ); + mapping = true; + break; + case TOROIDAL_TOK: + warp->setWarpType( PMWarp::Toroidal ); + mapping = true; + break; + case PLANAR_TOK: + nextToken( ); + warp->setWarpType( PMWarp::Planar ); + if( parseVector( vector ) ) + { + warp->setOrientation( vector ); + if( parseToken( ',' ) ) + { + if( !parseFloat( f_number ) ) + return false; + warp->setDistExp( f_number ); + } + } + parsedFirst = true; + break; + case DIST_EXP_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setDistExp( f_number ); + break; + case MAJOR_RADIUS_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + warp->setMajorRadius( f_number ); + break; + default: + break; + } + + if( mapping) + { + nextToken( ); + if( !parseVector( vector ) ) + return false; + warp->setOrientation( vector ); + parsedFirst = true; + mapping = false; + } + + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigment( PMPigment* pigment, bool parseOuter ) +{ + PMColor c; + PMSolidColor* sc; + int oldConsumed; + + if( parseOuter ) + { + if( !parseToken( PIGMENT_TOK, "pigment" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + } + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMSymbol* s = getSymbol( id ); + bool skipID = false; + + if( s ) + if( s->type( ) == PMSymbol::Value ) + skipID = true; + + if( !skipID ) + { + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !pigment->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( pigment ); + + switch( m_token ) + { + case '<': + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + if( parseColor( c ) ) + { + sc = new PMSolidColor( m_pPart ); + sc->setColor( c ); + if( !insertChild( sc, pigment ) ) + { + delete sc; + sc = 0; + } + } + break; + case UV_MAPPING_TOK: + nextToken(); + pigment->setUVMapping( parseBool( ) ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( parseOuter ) + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNormal( PMNormal* normal ) +{ + double f_number; + int oldConsumed; + + if( !parseToken( NORMAL_TOK, "normal" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !normal->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( normal ); + switch( m_token ) + { + case BUMP_SIZE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + normal->enableBumpSize( true ); + normal->setBumpSize( f_number ); + break; + case ACCURACY_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + normal->setAccuracy( f_number ); + break; + case UV_MAPPING_TOK: + nextToken( ); + normal->setUVMapping( parseBool( ) ); + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseTextureMap( PMTextureMap* textureMap ) +{ + int oldConsumed; + double f_number1; + PMTexture* texture; + QValueList<double> mapValues; + + if( !parseToken( TEXTURE_MAP_TOK, "texture_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !textureMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + texture = new PMTexture( m_pPart ); + + parseTexture( texture, false ); + + if( !insertChild( texture, textureMap ) ) + delete texture; + + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + textureMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigmentMap( PMPigmentMap* pigmentMap ) +{ + int oldConsumed; + double f_number1; + PMPigment* pigment; + QValueList<double> mapValues; + + if( !parseToken( PIGMENT_MAP_TOK, "pigment_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !pigmentMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + pigment = new PMPigment( m_pPart ); + + parsePigment( pigment, false ); + if( !insertChild( pigment, pigmentMap ) ) + delete pigment; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + pigmentMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseNormalMap( PMNormalMap* normalMap ) +{ + int oldConsumed; + double f_number1; + PMNormal* normal; + QValueList<double> mapValues; + + if( !parseToken( NORMAL_MAP_TOK, "normal_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !normalMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + normal = new PMNormal( m_pPart ); + if( !parseNormal( normal ) ) + { + delete normal; + return false; + } + if( !insertChild( normal, normalMap ) ) + delete normal; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + normalMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseBumpMap( PMBumpMap* bumpMap ) +{ + int oldConsumed; + int i_number; + double f_number; + + if( !parseToken( BUMP_MAP_TOK, "bump_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + bumpMap->setBitmapType( PMBumpMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + bumpMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case ONCE_TOK: + nextToken( ); + bumpMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + bumpMap->setMapType( PMBumpMap::MapPlanar ); + break; + case 1: + bumpMap->setMapType( PMBumpMap::MapSpherical ); + break; + case 2: + bumpMap->setMapType( PMBumpMap::MapCylindrical ); + break; + case 5: + bumpMap->setMapType( PMBumpMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + bumpMap->setInterpolateType( PMBumpMap::InterpolateBilinear ); + break; + case 4: + bumpMap->setInterpolateType( PMBumpMap::InterpolateNormalized ); + break; + } + break; + case USE_INDEX_TOK: + nextToken( ); + bumpMap->enableUseIndex( true ); + break; + case BUMP_SIZE_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + bumpMap->setBumpSize( f_number ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMaterialMap( PMMaterialMap* materialMap ) +{ + int oldConsumed; + int i_number; + + if( !parseToken( MATERIAL_MAP_TOK, "material_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + materialMap->setBitmapType( PMMaterialMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + materialMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( materialMap ); + switch( m_token ) + { + case ONCE_TOK: + nextToken( ); + materialMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + materialMap->setMapType( PMMaterialMap::MapPlanar ); + break; + case 1: + materialMap->setMapType( PMMaterialMap::MapSpherical ); + break; + case 2: + materialMap->setMapType( PMMaterialMap::MapCylindrical ); + break; + case 5: + materialMap->setMapType( PMMaterialMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + materialMap->setInterpolateType( PMMaterialMap::InterpolateBilinear ); + break; + case 4: + materialMap->setInterpolateType( PMMaterialMap::InterpolateNormalized ); + break; + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSlopeMap( PMSlopeMap* slopeMap ) +{ + int oldConsumed; + double f_number1; + PMSlope* slope; + QValueList<double> mapValues; + + if( !parseToken( SLOPE_MAP_TOK, "slope_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !slopeMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + slope = new PMSlope( m_pPart ); + if( !parseSlope( slope ) ) + { + delete slope; + return false; + } + if( !insertChild( slope, slopeMap ) ) + delete slope; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + slopeMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDensityMap( PMDensityMap* densityMap ) +{ + int oldConsumed; + double f_number1; + PMDensity* density; + QValueList<double> mapValues; + + if( !parseToken( DENSITY_MAP_TOK, "density_map" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !densityMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + // If we find '}' no need to search for an entry + if( m_token != '}' && parseToken( '[' ) ) + { + if( !parseFloat( f_number1 ) ) + return false; + mapValues.append( f_number1 ); + density = new PMDensity( m_pPart ); + if( !parseDensity( density ) ) + { + delete density; + return false; + } + if( !insertChild( density, densityMap ) ) + delete density; + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + densityMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseImageMap( PMImageMap* imageMap ) +{ + int oldConsumed; + int i_number; + double f_number; + PMPaletteValue newPaletteValue; + QValueList<PMPaletteValue> l_valuesFilter; + QValueList<PMPaletteValue> l_valuesTransmit; + + if( !parseToken( IMAGE_MAP_TOK, "image_map" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + // Parse the bitmap type + if( m_token != STRING_TOK ) + { + switch( m_token ) + { + case GIF_TOK: + imageMap->setBitmapType( PMImageMap::BitmapGif ); + nextToken( ); + break; + case TGA_TOK: + imageMap->setBitmapType( PMImageMap::BitmapTga ); + nextToken( ); + break; + case IFF_TOK: + imageMap->setBitmapType( PMImageMap::BitmapIff ); + nextToken( ); + break; + case PPM_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPpm ); + nextToken( ); + break; + case PGM_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPgm ); + nextToken( ); + break; + case PNG_TOK: + imageMap->setBitmapType( PMImageMap::BitmapPng ); + nextToken( ); + break; + case SYS_TOK: + imageMap->setBitmapType( PMImageMap::BitmapSys ); + nextToken( ); + break; + default: + printError( i18n( "Unknown bitmap type" ) ); + return false; + } + } + + // Parse the bitmap file name + if( m_token != STRING_TOK ) + { + printError( i18n( "Expecting a file name." ) ); + return false; + } + else + { + imageMap->setBitmapFileName( m_pScanner->sValue( ) ); + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case TRANSMIT_TOK: + nextToken( ); + if( m_token == ALL_TOK ) + { + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + imageMap->enableTransmitAll( true ); + imageMap->setTransmitAll( f_number ); + } + else + { + if( !parseInt( i_number ) ) + return false; + parseToken( ',' ); + if( !parseFloat( f_number ) ) + return false; + newPaletteValue.setIndex( i_number ); + newPaletteValue.setValue( f_number ); + l_valuesTransmit.append( newPaletteValue ); + } + break; + case FILTER_TOK: + nextToken( ); + if( m_token == ALL_TOK ) + { + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + imageMap->enableFilterAll( true ); + imageMap->setFilterAll( f_number ); + } + else + { + if( !parseInt( i_number ) ) + return false; + parseToken( ',' ); + if( !parseFloat( f_number ) ) + return false; + newPaletteValue.setIndex( i_number ); + newPaletteValue.setValue( f_number ); + l_valuesFilter.append( newPaletteValue ); + } + break; + case ONCE_TOK: + nextToken( ); + imageMap->enableOnce( true ); + break; + case MAP_TYPE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 0: + imageMap->setMapType( PMImageMap::MapPlanar ); + break; + case 1: + imageMap->setMapType( PMImageMap::MapSpherical ); + break; + case 2: + imageMap->setMapType( PMImageMap::MapCylindrical ); + break; + case 5: + imageMap->setMapType( PMImageMap::MapToroidal ); + break; + } + break; + case INTERPOLATE_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + switch( i_number ) + { + case 2: + imageMap->setInterpolateType( PMImageMap::InterpolateBilinear ); + break; + case 4: + imageMap->setInterpolateType( PMImageMap::InterpolateNormalized ); + break; + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + imageMap->setFilters( l_valuesFilter ); + imageMap->setTransmits( l_valuesTransmit ); + + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePigmentList( PMPigmentList* pigmentList, int expectedItems ) +{ + int oldConsumed; + PMPigment* pigment; + + do + { + oldConsumed = m_consumedTokens; + pigment = new PMPigment( m_pPart ); + if( !parsePigment( pigment ) ) + { + delete pigment; + return false; + } + if( !insertChild( pigment, pigmentList ) ) + delete pigment; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseColorList( PMColorList* colorList, int expectedItems ) +{ + int oldConsumed; + PMColor color; + PMSolidColor* sc; + + do + { + oldConsumed = m_consumedTokens; + if( !parseColor( color ) ) + { + return false; + } + sc = new PMSolidColor( m_pPart ); + sc->setColor( color ); + if( !insertChild( sc, colorList ) ) + delete sc; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseNormalList( PMNormalList* normalList, int expectedItems ) +{ + int oldConsumed; + PMNormal* normal; + + do + { + oldConsumed = m_consumedTokens; + normal = new PMNormal( m_pPart ); + if( !parseNormal( normal ) ) + { + delete normal; + return false; + } + if( !insertChild( normal, normalList ) ) + delete normal; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseTextureList( PMTextureList* textureList, int expectedItems ) +{ + int oldConsumed; + PMTexture* texture; + + do + { + oldConsumed = m_consumedTokens; + texture = new PMTexture( m_pPart ); + if( !parseTexture( texture ) ) + { + delete texture; + return false; + } + if( !insertChild( texture, textureList ) ) + delete texture; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseDensityList( PMDensityList* densityList, int expectedItems ) +{ + int oldConsumed; + PMDensity* density; + + do + { + oldConsumed = m_consumedTokens; + density = new PMDensity( m_pPart ); + if( !parseDensity( density ) ) + { + delete density; + return false; + } + if( !insertChild( density, densityList ) ) + delete density; + + // In the last entry don't expect a comma + if( expectedItems-- ) + if( m_token == ',' ) + nextToken( ); + } + while( oldConsumed != m_consumedTokens && expectedItems ); + + return true; +} + +bool PMPovrayParser::parseColorMap( PMColorMap* colorMap ) +{ + int oldConsumed; + double f_number1, f_number2; + PMColor color1, color2; + PMSolidColor* solidColor; + PMSolidColor* lastColor = 0; + QValueList<double> mapValues; + bool newEntry; + bool twoColors; + + if( m_token != COLOR_MAP_TOK && m_token != COLOUR_MAP_TOK ) + return false; + nextToken( ); + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !colorMap->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + + if( m_token == '[' ) + { + nextToken( ); + if( !parseFloat( f_number1 ) ) + return false; + + twoColors = false; + if( m_token == ',' ) + { + twoColors = true; + nextToken( ); + } + else if( ( m_token == INTEGER_TOK ) || ( m_token == FLOAT_TOK ) ) + twoColors = true; + + if( twoColors ) + { + // Two colors in the same entry + + if( parseFloat( f_number2 ) ) + { + if( !parseColor( color1 ) ) + return false; + if( !parseColor( color2 ) ) + return false; + // If the first value doesn't pick up from the previous, + // or the color is different... + newEntry = true; + if( lastColor && !mapValues.isEmpty( ) ) + if( ( mapValues.last( ) == f_number1 ) && + ( lastColor->color( ) == color1 ) ) + newEntry = false; + + if( newEntry ) + { + // ... add the two colors in two different entries ... + mapValues.append( f_number1 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color1 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + + mapValues.append( f_number2 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color2 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + else + { + // ... else just add the last value and color + mapValues.append( f_number2 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color2 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + } + } + else + { + // Only one color in the entry + if( !parseColor( color1 ) ) + return false; + mapValues.append( f_number1 ); + solidColor = new PMSolidColor( m_pPart ); + solidColor->setColor( color1 ); + if( !insertChild( solidColor, colorMap ) ) + delete solidColor; + else + lastColor = solidColor; + } + if( !parseToken( ']' ) ) + return false; + } + } + while( oldConsumed != m_consumedTokens ); + + colorMap->setMapValues( mapValues ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSkySphere( PMSkySphere* sky ) +{ + int oldConsumed; + + if( !parseToken( SKY_SPHERE_TOK, "sky_sphere" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !sky->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( sky ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRainbow( PMRainbow* rainbow ) +{ + PMVector vector; + double f_number; + int oldConsumed; + + if( !parseToken( RAINBOW_TOK, "rainbow" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !rainbow->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( rainbow ); + switch( m_token ) + { + case DIRECTION_TOK: + nextToken( ); + if( parseVector( vector ) ) + { + rainbow->enableDirection( true ); + rainbow->setDirection( vector ); + } + break; + case ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableAngle( true ); + rainbow->setAngle( f_number ); + } + break; + case WIDTH_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableWidth( true ); + rainbow->setWidth( f_number ); + } + break; + case DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableDistance( true ); + rainbow->setDistance( f_number ); + } + break; + case JITTER_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableJitter( true ); + rainbow->setJitter( f_number ); + } + break; + case UP_TOK: + nextToken( ); + if( parseVector( vector ) ) + { + rainbow->enableUp( true ); + rainbow->setUp( vector ); + } + break; + case ARC_ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableArcAngle( true ); + rainbow->setArcAngle( f_number ); + } + break; + case FALLOFF_ANGLE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + rainbow->enableFalloffAngle( true ); + rainbow->setFalloffAngle( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseFog( PMFog* fog ) +{ + PMColor color; + PMVector vector; + double f_number; + int i_number; + int fog_type; + int oldConsumed; + + if( !parseToken( FOG_TOK, "fog" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !fog->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + fog_type = 1; + if( parseToken( FOG_TYPE_TOK, "fog_type" ) ) + { + if( !parseInt( i_number ) ) + return false; + fog_type = i_number; + } + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + fog->setDistance( f_number ); + break; + case '<': + case COLOR_TOK: + case COLOUR_TOK: + case RGB_TOK: + case RGBT_TOK: + case RGBF_TOK: + case RGBFT_TOK: + case RED_TOK: + case GREEN_TOK: + case BLUE_TOK: + case TRANSMIT_TOK: + case FILTER_TOK: + case ID_TOK: + if( parseColor( color ) ) + fog->setColor( color ); + break; + case TURBULENCE_TOK: + nextToken( ); + fog->enableTurbulence( true ); + if( !parseVector( vector ) ) + return false; + fog->setValueVector( vector ); + break; + case OCTAVES_TOK: + nextToken( ); + if( !parseInt( i_number ) ) + return false; + fog->setOctaves( i_number ); + break; + case OMEGA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setOmega( f_number ); + break; + case LAMBDA_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setLambda( f_number ); + break; + case TURB_DEPTH_TOK: + nextToken( ); + if( !parseFloat( f_number ) ) + return false; + fog->setDepth( f_number ); + break; + case FOG_OFFSET_TOK: + nextToken( ); + fog_type = 2; + if( parseFloat( f_number ) ) + fog->setFogOffset( f_number ); + break; + case FOG_ALT_TOK: + nextToken( ); + fog_type = 2; + if( parseFloat( f_number ) ) + fog->setFogAlt( f_number ); + break; + case UP_TOK: + nextToken( ); + fog_type = 2; + if( !parseVector( vector ) ) + return false; + fog->setUp( vector ); + break; + default: + break; + } + // Only parseChildObjects() if the token is not turbulence, because this + // function parses that token. + if( m_token != TURBULENCE_TOK ) + parseChildObjects( fog ); + } + while( oldConsumed != m_consumedTokens ); + + fog->setFogType( fog_type ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMedia( PMMedia* media ) +{ + PMColor color; + double f_number; + int i_number; + int oldConsumed, oldConsumed1; + + if( !parseToken( MEDIA_TOK, "media" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !media->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( media ); + switch( m_token ) + { + case METHOD_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setMethod( i_number ); + break; + case INTERVALS_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setIntervals( i_number ); + break; + case SAMPLES_TOK: + nextToken( ); + if( parseInt( i_number ) ) + media->setSamplesMin( i_number ); + parseToken( ',' ); + if( parseInt( i_number ) ) + media->setSamplesMax( i_number ); + break; + case CONFIDENCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setConfidence( f_number ); + break; + case VARIANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setVariance( f_number ); + break; + case RATIO_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setRatio( f_number ); + break; + case AA_LEVEL_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + media->setAALevel( i_number ); + break; + case AA_THRESHOLD_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + media->setAAThreshold( f_number ); + break; + case ABSORPTION_TOK: + nextToken( ); + if( parseColor( color ) ) + { + media->enableAbsorption( true ); + media->setAbsorption( color ); + } + break; + case EMISSION_TOK: + nextToken( ); + media->enableEmission( true ); + if( parseColor( color ) ) + media->setEmission( color ); + break; + case SCATTERING_TOK: + nextToken( ); + parseToken( '{' ); + media->enableScattering( true ); + if( parseInt( i_number ) ) + media->setScatteringType( i_number ); + parseToken( ',' ); + if( parseColor( color ) ) + media->setScatteringColor( color ); + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case ECCENTRICITY_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setScatteringEccentricity( f_number ); + break; + case EXTINCTION_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + media->setScatteringExtinction( f_number ); + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDensity( PMDensity* density ) +{ + int oldConsumed; + + if( !parseToken( DENSITY_TOK, "density" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !density->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( density ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseInterior( PMInterior* interior ) +{ + double f_number; + int i_number; + int oldConsumed; + + if( !parseToken( INTERIOR_TOK, "interior" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !interior->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( interior ); + switch( m_token ) + { + case IOR_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableIor( true ); + interior->setIor( f_number ); + } + break; + case CAUSTICS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableCaustics( true ); + interior->setCaustics( f_number ); + } + break; + case DISPERSION_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + interior->enableDispersion( true ); + interior->setDispersion( f_number ); + } + break; + case DISPERSION_SAMPLES_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + { + interior->enableDispSamples( true ); + interior->setDispSamples( i_number ); + } + break; + case FADE_DISTANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableFadeDistance( true ); + interior->setFadeDistance( f_number ); + } + break; + case FADE_POWER_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + interior->enableFadePower( true ); + interior->setFadePower( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMaterial( PMMaterial* material ) +{ + int oldConsumed; + + if( !parseToken( MATERIAL_TOK, "material" ) ) + return false; + + if( !parseToken( '{' ) ) + return false; + + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !material->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( material ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSlope( PMSlope* slope ) +{ + double f_number; + + if( !parseToken( '<' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + slope->setHeight( f_number ); + if( !parseToken( ',' ) ) + return false; + if( !parseFloat( f_number ) ) + return false; + slope->setSlope( f_number ); + if( !parseToken( '>' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseGlobalSettings( PMGlobalSettings* globalsettings ) +{ + PMColor color; + double f_number; + int i_number; + int oldConsumed; + + // Initial global settings tokens + if( !parseToken( GLOBAL_SETTINGS_TOK, "global_settings" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse global settings tokens + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( globalsettings ); + + switch( m_token ) + { + case ADC_BAILOUT_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + globalsettings->setAdcBailout( f_number ); + break; + case AMBIENT_LIGHT_TOK: + nextToken( ); + if( parseColor( color ) ) + globalsettings->setAmbientLight( color ); + break; + case ASSUMED_GAMMA_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + globalsettings->setAssumedGamma( f_number ); + break; + case HF_GRAY_16_TOK: + nextToken( ); + switch( m_token ) + { + case ON_TOK: + globalsettings->setHfGray16( true ); + nextToken( ); + break; + case OFF_TOK: + globalsettings->setHfGray16( false ); + nextToken( ); + break; + default: + break; + } + break; + case IRID_WAVELENGTH_TOK: + nextToken( ); + if( parseColor( color ) ) + globalsettings->setIridWaveLength( color ); + break; + case MAX_INTERSECTIONS_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setMaxIntersections( i_number ); + break; + case MAX_TRACE_LEVEL_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setMaxTraceLevel( i_number ); + break; + case NUMBER_OF_WAVES_TOK: + nextToken( ); + if( parseInt( i_number ) ) + globalsettings->setNumberWaves( i_number ); + break; + case NOISE_GENERATOR_TOK: + nextToken( ); + if ( parseInt( i_number ) ) + globalsettings->setNoiseGenerator( + ( PMGlobalSettings::PMNoiseType ) ( i_number - 1 ) ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseFinish( PMFinish* finish ) +{ + PMColor color; + double f_number; + int oldConsumed, oldConsumed1; + + // Initial finish tokens "finish {" + if( !parseToken( FINISH_TOK, "finish" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + // Parse a possible declare link identifier + if( m_token == ID_TOK ) + { + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !finish->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + } + + // Parse finish tokens + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case AMBIENT_TOK: + nextToken( ); + finish->enableAmbient( true ); + if( parseColor( color ) ) + finish->setAmbientColor( color ); + break; + case DIFFUSE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableDiffuse( true ); + finish->setDiffuse( f_number ); + } + break; + case BRILLIANCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableBrilliance( true ); + finish->setBrilliance( f_number ); + } + break; + case PHONG_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enablePhong( true ); + finish->setPhong( f_number ); + } + break; + case PHONG_SIZE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enablePhongSize( true ); + finish->setPhongSize( f_number ); + } + break; + case METALLIC_TOK: + nextToken( ); + finish->enableMetallic( true ); + finish->setMetallic( 1.0 ); + if( parseFloat( f_number, true ) ) + finish->setMetallic( f_number ); + break; + case SPECULAR_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableSpecular( true ); + finish->setSpecular( f_number ); + } + break; + case ROUGHNESS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRoughness( true ); + finish->setRoughness( f_number ); + } + break; + case CRAND_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableCrand( true ); + finish->setCrand( f_number ); + } + break; + case CONSERVE_ENERGY_TOK: + nextToken( ); + finish->setConserveEnergy( parseBool( ) ); + break; + case REFLECTION_TOK: + nextToken( ); + finish->enableReflection( true ); + if( !parseToken( '{' ) ) + { + printError( i18n( "Using Old Reflection Syntax" ) ); + if( parseColor( color ) ) + finish->setReflectionColor( color ); + } + else if( parseColor( color ) ) + { + if( parseToken( ',' ) ) + { + finish->enableReflectionMin( true ); + finish->setReflectionMinColor( color ); + if( parseColor( color ) ) + finish->setReflectionColor( color ); + else + return false; + } + else + finish->setReflectionColor( color ); + + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case FRESNEL_TOK: + nextToken( ); + finish->setReflectionFresnel( parseBool( ) ); + break; + case FALLOFF_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRefFalloff( true ); + finish->setReflectionFalloff( f_number ); + } + break; + case EXPONENT_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + { + finish->enableRefExponent( true ); + finish->setReflectionExponent( f_number ); + } + break; + case METALLIC_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + finish->enableRefMetallic( true ); + finish->setReflectionMetallic( f_number ); + } + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + } + else + return false; + break; + case REFLECTION_EXPONENT_TOK: + nextToken( ); + if ( parseFloat( f_number ) ) + { + finish->enableRefExponent( true ); + finish->setReflectionExponent( f_number ); + } + break; + case IRID_TOK: + nextToken( ); + parseToken( '{' ); + finish->setIrid( true ); + if( parseFloat( f_number ) ) + finish->setIridAmount( f_number ); + do + { + oldConsumed1 = m_consumedTokens; + switch( m_token ) + { + case THICKNESS_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + finish->setIridThickness( f_number ); + break; + case TURBULENCE_TOK: + nextToken( ); + if( parseFloat( f_number ) ) + finish->setIridTurbulence( f_number ); + break; + default: + break; + } + } + while( oldConsumed1 != m_consumedTokens ); + parseToken( '}' ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseDeclare( PMDeclare* decl ) +{ + PMObject* child = 0; + PMTexture* texture = 0; + bool error = false; + + switch( m_token ) + { + case OBJECT_TOK: + error = !parseObject( decl ); + break; + // finite solid + case BLOB_TOK: + child = new PMBlob( m_pPart ); + error = !parseBlob( ( PMBlob* ) child ); + break; + case BOX_TOK: + child = new PMBox( m_pPart ); + error = !parseBox( ( PMBox* ) child ); + break; + case CONE_TOK: + child = new PMCone( m_pPart ); + error = !parseCone( ( PMCone* ) child ); + break; + case CYLINDER_TOK: + child = new PMCylinder( m_pPart ); + error = !parseCylinder( ( PMCylinder* ) child ); + break; + case HEIGHT_FIELD_TOK: + child = new PMHeightField( m_pPart ); + error = !parseHeightField( ( PMHeightField* ) child ); + break; + case JULIA_FRACTAL_TOK: + child = new PMJuliaFractal( m_pPart ); + error = !parseJuliaFractal( ( PMJuliaFractal* ) child ); + break; + case LATHE_TOK: + child = new PMLathe( m_pPart ); + error = !parseLathe( ( PMLathe* ) child ); + break; + case PRISM_TOK: + child = new PMPrism( m_pPart ); + error = !parsePrism( ( PMPrism* ) child ); + break; + case SPHERE_TOK: + child = new PMSphere( m_pPart ); + error = !parseSphere( ( PMSphere* ) child ); + break; + case SUPERELLIPSOID_TOK: + child = new PMSuperquadricEllipsoid( m_pPart ); + error = !parseSqe( ( PMSuperquadricEllipsoid* ) child ); + break; + case SOR_TOK: + child = new PMSurfaceOfRevolution( m_pPart ); + error = !parseSor( ( PMSurfaceOfRevolution* ) child ); + break; + case TEXT_TOK: + child = new PMText( m_pPart ); + error = !parseText( ( PMText* ) child ); + break; + case TORUS_TOK: + child = new PMTorus( m_pPart ); + error = !parseTorus( ( PMTorus* ) child ); + break; + // finite patch + case BICUBIC_PATCH_TOK: + child = new PMBicubicPatch( m_pPart ); + error = !parseBicubicPatch( ( PMBicubicPatch* ) child ); + break; + case DISC_TOK: + child = new PMDisc( m_pPart ); + error = !parseDisc( ( PMDisc* ) child ); + break; + case TRIANGLE_TOK: + case SMOOTH_TRIANGLE_TOK: + child = new PMTriangle( m_pPart ); + error = !parseTriangle( ( PMTriangle* ) child ); + break; + // infinite solid + case PLANE_TOK: + child = new PMPlane( m_pPart ); + error = !parsePlane( ( PMPlane* ) child ); + break; + case QUADRIC_TOK: + case CUBIC_TOK: + case QUARTIC_TOK: + case POLY_TOK: + child = new PMPolynom( m_pPart ); + error = !parsePolynom( ( PMPolynom* ) child ); + break; + // csg + case UNION_TOK: + case DIFFERENCE_TOK: + case INTERSECTION_TOK: + case MERGE_TOK: + child = new PMCSG( m_pPart ); + error = !parseCSG( ( PMCSG* ) child ); + break; + // textures + case TEXTURE_TOK: + while( m_token == TEXTURE_TOK ) + { + texture = new PMTexture( m_pPart ); + if( !parseTexture( texture ) ) + error = true; + if( !insertChild( texture, decl ) ) + { + delete texture; + texture = 0; + } + } + break; + case PIGMENT_TOK: + child = new PMPigment( m_pPart ); + error = !parsePigment( ( PMPigment* ) child ); + break; + case NORMAL_TOK: + child = new PMNormal( m_pPart ); + error = !parseNormal( ( PMNormal* ) child ); + break; + case FINISH_TOK: + child = new PMFinish( m_pPart ); + error = !parseFinish( ( PMFinish* ) child ); + break; + case TEXTURE_MAP_TOK: + child = new PMTextureMap( m_pPart ); + error = !parseTextureMap( ( PMTextureMap* ) child ); + break; + case PIGMENT_MAP_TOK: + child = new PMPigmentMap( m_pPart ); + error = !parsePigmentMap( ( PMPigmentMap* ) child ); + break; + case COLOR_MAP_TOK: + case COLOUR_MAP_TOK: + child = new PMColorMap( m_pPart ); + error = !parseColorMap( ( PMColorMap* ) child ); + break; + case NORMAL_MAP_TOK: + child = new PMNormalMap( m_pPart ); + error = !parseNormalMap( ( PMNormalMap* ) child ); + break; + case SLOPE_MAP_TOK: + child = new PMSlopeMap( m_pPart ); + error = !parseSlopeMap( ( PMSlopeMap* ) child ); + break; + case DENSITY_MAP_TOK: + child = new PMDensityMap( m_pPart ); + error = !parseDensityMap( ( PMDensityMap* ) child ); + break; + case INTERIOR_TOK: + child = new PMInterior( m_pPart ); + error = !parseInterior( ( PMInterior* ) child ); + break; + case MEDIA_TOK: + child = new PMMedia( m_pPart ); + error = !parseMedia( ( PMMedia* ) child ); + break; + case DENSITY_TOK: + child = new PMDensity( m_pPart ); + error = !parseDensity( ( PMDensity* ) child ); + break; + case MATERIAL_TOK: + child = new PMMaterial( m_pPart ); + error = !parseMaterial( ( PMMaterial* ) child ); + break; + case SKY_SPHERE_TOK: + child = new PMSkySphere( m_pPart ); + error = !parseSkySphere( ( PMSkySphere* ) child ); + break; + case RAINBOW_TOK: + child = new PMRainbow( m_pPart ); + error = !parseRainbow( ( PMRainbow* ) child ); + break; + case FOG_TOK: + child = new PMFog( m_pPart ); + error = !parseFog( ( PMFog* ) child ); + break; + // misc + case LIGHT_SOURCE_TOK: + child = new PMLight( m_pPart ); + error = !parseLight( ( PMLight* ) child ); + break; + case ISOSURFACE_TOK: + child = new PMIsoSurface( m_pPart ); + error = !parseIsoSurface( ( PMIsoSurface* ) child ); + break; + case PHOTONS_TOK: + child = new PMPhotons( m_pPart ); + error = !parsePhotons( ( PMPhotons* ) child ); + break; + case LIGHT_GROUP_TOK: + child = new PMLightGroup( m_pPart ); + error = !parseLightGroup( ( PMLightGroup* ) child ); + break; + case INTERIOR_TEXTURE_TOK: + child = new PMInteriorTexture( m_pPart ); + error = !parseInteriorTexture( ( PMInteriorTexture* ) child ); + break; + case SPHERE_SWEEP_TOK: + child = new PMSphereSweep( m_pPart ); + error = !parseSphereSweep( ( PMSphereSweep* ) child ); + break; + case MESH_TOK: + child = new PMMesh( m_pPart ); + error = !parseMesh( ( PMMesh* ) child ); + break; + } + + if( child ) + { + if( !insertChild( child, decl ) ) + { + delete child; + child = 0; + } + } + return !error; +} + +bool PMPovrayParser::parseObject( PMCompositeObject* parent ) +{ + PMObject* child; + bool error = false; + if( !parseToken( OBJECT_TOK, "object" ) ) + return false; + + if( parseToken( '{' ) ) + { + switch( m_token ) + { + case ID_TOK: + child = new PMObjectLink( m_pPart ); + error = !parseObjectLink( ( PMObjectLink* ) child ); + if( !insertChild( child, parent ) ) + delete child; + break; + default: + { + PMObject* lastChild = 0; + if( parent ) + lastChild = parent->lastChild( ); + else + lastChild = m_pResultList->last( ); + + error = !parseChildObjects( parent, 1 ); + if( !error ) + { + PMObject* newLast = 0; + if( parent ) + newLast = parent->lastChild( ); + else + newLast = m_pResultList->last( ); + + if( newLast && ( newLast != lastChild ) && + newLast->isA( "CompositeObject" ) ) + { + // one child was parsed + // append all following objects + error = !parseChildObjects( ( PMCompositeObject* ) newLast ); + } + else + { + printError( i18n( "One graphical object expected" ) ); + error = true; + } + } + break; + } + } + if( !parseToken( '}' )) + error = true; + } + else + error = true; + return !error; +} + +bool PMPovrayParser::parseObjectLink( PMObjectLink* link ) +{ + int oldConsumed; + + if( m_token != ID_TOK ) + { + printExpected( "identifier", m_pScanner->sValue( ) ); + return false; + } + + QString id( m_pScanner->sValue( ) ); + PMDeclare* decl = checkLink( id ); + if( decl ) + { + if( !link->setLinkedObject( decl ) ) + printError( i18n( "Wrong declare type" ) ); + } + nextToken( ); + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( link ); + parseObjectModifiers( link ); + } + while( oldConsumed != m_consumedTokens ); + + return true; +} + +bool PMPovrayParser::parseIsoSurface( PMIsoSurface* iso ) +{ + PMVector vector; + double f; + int i; + int oldConsumed; + + if( !parseToken( ISOSURFACE_TOK, "isosurface" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( iso ); + parseObjectModifiers( iso ); + + switch( m_token ) + { + case FUNCTION_TOK: + nextToken( ); + if( m_token != '{' ) + { + printExpected( '{', m_pScanner->sValue( ) ); + return false; + } + + m_pScanner->scanFunction( ); + nextToken( ); + if( m_token != FUNCTION_TOK ) + return false; + iso->setFunction( QString( m_pScanner->sValue( ) ).simplifyWhiteSpace( ) ); + + nextToken( ); + parseToken( '}' ); + + break; + case CONTAINED_BY_TOK: + nextToken( ); + + if( !parseToken( '{' ) ) + return false; + + if( m_token == BOX_TOK ) + { + iso->setContainedBy( PMIsoSurface::Box ); + nextToken( ); + parseToken( '{' ); + if( parseVector( vector ) ) + iso->setCorner1( vector ); + parseToken( ',' ); + if( parseVector( vector ) ) + iso->setCorner2( vector ); + if( !parseToken( '}' ) ) + return false; + } + else if( m_token == SPHERE_TOK ) + { + iso->setContainedBy( PMIsoSurface::Sphere ); + nextToken( ); + parseToken( '{' ); + if( parseVector( vector ) ) + iso->setCenter( vector ); + parseToken( ',' ); + if( parseFloat( f ) ) + iso->setRadius( f ); + if( !parseToken( '}' ) ) + return false; + } + else + { + printUnexpected( m_pScanner->sValue( ) ); + return false; + } + + if( !parseToken( '}' ) ) + return false; + break; + case THRESHOLD_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setThreshold( f ); + break; + case ACCURACY_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setAccuracy( f ); + break; + case MAX_GRADIENT_TOK: + nextToken( ); + if( parseFloat( f ) ) + iso->setMaxGradient( f ); + break; + case EVALUATE_TOK: + nextToken( ); + iso->setEvaluate( true ); + if( parseFloat( f ) ) + { + iso->setEvaluateValue( 0, f ); + if( parseToken( ',' ) && parseFloat( f ) ) + { + iso->setEvaluateValue( 1, f ); + if( parseToken( ',' ) && parseFloat( f ) ) + iso->setEvaluateValue( 2, f ); + } + } + break; + case OPEN_TOK: + nextToken( ); + iso->setOpen( true ); + break; + case MAX_TRACE_TOK: + nextToken( ); + if( parseInt( i ) ) + iso->setMaxTrace( i ); + break; + case ALL_INTERSECTIONS_TOK: + nextToken( ); + iso->setAllIntersections( true ); + break; + default: + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseRadiosity( PMRadiosity* rad ) +{ + double f; + int i; + int oldConsumed; + + + if( !parseToken( RADIOSITY_TOK, "radiosity" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case ADC_BAILOUT_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setAdcBailout( f ); + break; + case ALWAYS_SAMPLE_TOK: + nextToken( ); + rad->setAlwaysSample( parseBool( ) ); + break; + case BRIGHTNESS_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setBrightness( f ); + break; + case COUNT_TOK: + nextToken( ); + if( parseInt( i ) ) + rad->setCount( i ); + break; + case ERROR_BOUND_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setErrorBound( f ); + break; + case GRAY_THRESHOLD_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setGrayThreshold( f ); + break; + case LOW_ERROR_FACTOR_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setLowErrorFactor( f ); + break; + case MAX_SAMPLE_TOK: + nextToken( ); + if ( parseFloat( f ) ) + rad->setMaxSample( f ); + break; + case MEDIA_TOK: + nextToken( ); + rad->setMedia( parseBool( ) ); + break; + case MINIMUM_REUSE_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setMinimumReuse( f ); + break; + case NEAREST_COUNT_TOK: + nextToken( ); + if( parseInt( i ) ) + rad->setNearestCount( i ); + break; + case NORMAL_TOK: + nextToken( ); + rad->setNormal( parseBool( ) ); + break; + case PRETRACE_START_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setPretraceStart( f ); + break; + case PRETRACE_END_TOK: + nextToken( ); + if( parseFloat( f ) ) + rad->setPretraceEnd( f ); + break; + case RECURSION_LIMIT_TOK: + nextToken( ); + if( parseInt( i) ) + rad->setRecursionLimit( i ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseGlobalPhotons( PMGlobalPhotons* gp ) +{ + double f; + int i; + int oldConsumed; + + + if( !parseToken( PHOTONS_TOK, "photons" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case SPACING_TOK: + gp->setNumberType( PMGlobalPhotons::Spacing ); + nextToken( ); + if ( parseFloat( f ) ) + gp->setSpacing( f ); + break; + case COUNT_TOK: + gp->setNumberType( PMGlobalPhotons::Count ); + nextToken( ); + if ( parseInt( i ) ) + gp->setCount( i ); + break; + case GATHER_TOK: + nextToken( ); + if ( parseInt( i ) ) + { + gp->setGatherMin( i ); + if ( parseToken( ',' ) && parseInt( i ) ) + gp->setGatherMax( i ); + } + break; + case MEDIA_TOK: + nextToken( ); + if ( parseInt( i ) ) + { + gp->setMediaMaxSteps( i ); + if ( parseToken( ',' ) && parseFloat( f ) ) + gp->setMediaFactor( f ); + } + case JITTER_TOK: + nextToken( ); + if ( parseFloat( f ) ) + gp->setJitter( f ); + break; + case MAX_TRACE_LEVEL_TOK: + nextToken( ); + gp->setMaxTraceLevelGlobal( false ); + if ( parseInt( i ) ) + gp->setMaxTraceLevel( i ); + break; + case ADC_BAILOUT_TOK: + nextToken( ); + gp->setAdcBailoutGlobal( false ); + if ( parseFloat( f ) ) + gp->setAdcBailout( f ); + break; + case AUTOSTOP_TOK: + nextToken( ); + if ( parseFloat( f ) ) + gp->setAutostop( f ); + break; + case EXPAND_THRESHOLDS_TOK: + nextToken( ); + if ( parseFloat( f ) ) + { + gp->setExpandIncrease( f ); + if ( parseToken( ',' ) && parseInt( i ) ) + gp->setExpandMin( i ); + } + break; + case RADIUS_TOK: + nextToken( ); + if ( parseFloat( f ) ) + { + gp->setRadiusGather( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + { + gp->setRadiusGatherMulti( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + { + gp->setRadiusMedia( f ); + if ( parseToken( ',' ) && parseFloat( f ) ) + gp->setRadiusMediaMulti( f ); + } + } + } + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parsePhotons( PMPhotons* p ) +{ + double f; + int oldConsumed; + + if( !parseToken( PHOTONS_TOK, "photons" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + p->setTarget( false ); + + do + { + oldConsumed = m_consumedTokens; + switch( m_token ) + { + case TARGET_TOK: + nextToken( ); + p->setTarget( true ); + if ( parseFloat( f ) ) + p->setSpacingMulti( f ); + break; + case REFRACTION_TOK: + nextToken( ); + p->setRefraction( parseBool( ) ); + break; + case REFLECTION_TOK: + nextToken( ); + p->setReflection( parseBool( ) ); + break; + case COLLECT_TOK: + nextToken( ); + p->setCollect( parseBool( ) ); + break; + case PASS_THROUGH_TOK: + nextToken( ); + p->setPassThrough( parseBool( ) ); + break; + case AREA_LIGHT_TOK: + nextToken( ); + p->setAreaLight( parseBool( ) ); + break; + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseLightGroup( PMLightGroup* lg ) +{ + int oldConsumed; + + if ( !parseToken( LIGHT_GROUP_TOK, "light_group" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == GLOBAL_LIGHTS_TOK ) + { + nextToken( ); + lg->setGlobalLights( parseBool( ) ); + } + else + { + parseChildObjects( lg ); + parseObjectModifiers( lg ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseInteriorTexture( PMInteriorTexture* it ) +{ + int oldConsumed; + + if( !parseToken( INTERIOR_TEXTURE_TOK, "interior_texture" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + parseChildObjects( it ); + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseSphereSweep( PMSphereSweep* ss ) +{ + int oldConsumed, numspheres; + QValueList<PMVector> points; + QValueList<double> radii; + PMVector point; + double f; + + if( !parseToken( SPHERE_SWEEP_TOK, "sphere_sweep" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + nextToken( ); + switch ( m_token ) + { + case LINEAR_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::LinearSpline ); + break; + case B_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::BSpline ); + break; + case CUBIC_SPLINE_TOK: + ss->setSplineType( PMSphereSweep::CubicSpline ); + break; + default: + return false; + } + + if ( !parseInt( numspheres ) ) + return false; + + for ( int i = 0; i < numspheres; ++i ) + { + if ( !parseVector( point ) ) + return false; + points.append( point ); + if ( !parseToken( ',' ) ) + return false; + if ( !parseFloat( f ) ) + return false; + radii.append( f ); + } + + ss->setPoints( points ); + ss->setRadii( radii ); + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == TOLERANCE_TOK ) + { + nextToken( ); + if ( !parseFloat( f ) ) + return false; + ss->setTolerance( f ); + } + else + { + parseObjectModifiers( ss ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} + +bool PMPovrayParser::parseMesh( PMMesh* m ) +{ + int oldConsumed; + PMVector vector; + + if( !parseToken( MESH_TOK, "mesh" ) ) + return false; + if( !parseToken( '{' ) ) + return false; + + do + { + oldConsumed = m_consumedTokens; + if ( m_token == HIERARCHY_TOK ) + { + nextToken( ); + m->setHierarchy( parseBool( ) ); + } + else if ( m_token == INSIDE_VECTOR_TOK ) + { + nextToken( ); + if ( !parseVector( vector ) ) + return false; + m->enableInsideVector( true ); + m->setInsideVector( vector ); + } + else + { + parseChildObjects( m ); + parseObjectModifiers( m ); + } + } + while( oldConsumed != m_consumedTokens ); + + if( !parseToken( '}' ) ) + return false; + + return true; +} |