Ejemplo n.º 1
0
void Plant::draw( Vector3D *inPosition, double inScale,
                  double inMaxZ, double inMinZ ) {


    if( mPoisoned && mPoisonStatus >= 1) {
        // draw nothing
        return;
        }

    
    double drawScale = inScale;

    if( mPoisoned ) {
        // shrink with poisoning
        
        drawScale *= ( 1 - mPoisonStatus );
        }

    
    double radius = drawScale * ( mGrowth * 0.8 + 0.2 );


    // leaves become black with poisoning
    // (shades of white to allow texture color to dominate) 
    Color leafColor( 1 - mPoisonStatus,
                     1 - mPoisonStatus,
                     1 - mPoisonStatus, 1 );

    
    if( ! Features::drawNicePlantLeaves ) {
        // set color to shades of green green for leaves if we're drawing
        // simple boxes, since there's no texture color

        leafColor.setValues( 0, 1 - mPoisonStatus, 0, 1 );
        }

    
    Angle3D zeroAngle( 0, 0, 0 );
    

    PlantGenetics *genetics = &( mSeeds.mGenetics );

    
    
    int maxNumJoints = (int)( genetics->getParameter( jointCount ) );

    double growthFactor = mGrowth * 0.8 + 0.2;
    
    int numFullJoints = (int)( growthFactor * maxNumJoints );

    double partialJoint = growthFactor * maxNumJoints - numFullJoints;

    int numLeavesPerJoint = (int)( genetics->getParameter( leavesPerJoint ) );

    Angle3D angleIncrement( 0, 0, 2 * M_PI / numLeavesPerJoint );
    Angle3D startAngle( 0, 0, mStartZAngle );

    double currentScale = 1;

    double scaleDecrement = currentScale / ( maxNumJoints + 1 );

    Vector3D leafPosition( inPosition );

    Vector3D positionIncrement( 0, 0, -0.5 );

    Vector3D leafWalkerTerminus;

    SimpleVector<Vector3D *> thisLayerLeafTerminii;
    
    
    for( int j=0; j<numFullJoints; j++ ) {

        // lower leaves are darker
        double colorScaleFactor = (double)(j+1) / (double)maxNumJoints; 
        // min scaling of 0.5
        colorScaleFactor = colorScaleFactor * 0.5 + 0.5;
        
        
        Color thisLevelColor;
        thisLevelColor.setValues( &leafColor );
        thisLevelColor.weightColor( colorScaleFactor );
        
        
        
        
        Angle3D currentAngle( &startAngle );

        double zValue = leafPosition.mZ;

        if( zValue <= inMaxZ && zValue >= inMaxZ ) {
            // draw this joint
            for( int g=0; g<numLeavesPerJoint; g++ ) {

                if( Features::drawShadows ) {
                    // draw shadow
                    glColor4f( 0, 0, 0, 0.5 );
                    mLeaf.draw( &leafPosition, &currentAngle,
                                currentScale * radius * 1.05 );
                    }
                
                // draw leaf
                setGLColor( &thisLevelColor );
                
                mLeaf.draw( &leafPosition, &currentAngle,
                            currentScale * radius,
                            &leafWalkerTerminus );


                thisLayerLeafTerminii.push_back(
                    new Vector3D( &leafWalkerTerminus ) );

                
                currentAngle.add( &angleIncrement );
                }

            // finally cap this joint
            setGLColor( &thisLevelColor );
            mJointCapTexture->enable();
            glBegin( GL_QUADS ); {

                double capRadius = currentScale * radius * 0.1;
                double capZ = leafPosition.mZ;
                
                glTexCoord2f( 0, 0 );
                glVertex3d( leafPosition.mX - capRadius,
                            leafPosition.mY - capRadius, capZ );

                glTexCoord2f( 1, 0 );
                glVertex3d( leafPosition.mX + capRadius,
                            leafPosition.mY - capRadius, capZ );
                
                glTexCoord2f( 1, 1 );
                glVertex3d( leafPosition.mX + capRadius,
                            leafPosition.mY + capRadius, capZ );

                glTexCoord2f( 0, 1 );
                glVertex3d( leafPosition.mX - capRadius,
                            leafPosition.mY + capRadius, capZ );
                }
            glEnd();
            mJointCapTexture->disable();        
            }
        
        
        Angle3D angleToNextJoint( &angleIncrement );

        angleToNextJoint.scale( 0.5 );

        currentAngle.add( &angleToNextJoint );

        // start next joint at our current angle
        startAngle.setComponents( &currentAngle );

        currentScale -= scaleDecrement;

        leafPosition.add( &positionIncrement );
        }

    if( partialJoint > 0 ) {
        Angle3D currentAngle( &startAngle );

        // darker as growing completes


        // lower leaves are darker
        double colorScaleFactor =
            (double)(numFullJoints+1) / (double)maxNumJoints; 

        // min scaling of 0.5
        colorScaleFactor = colorScaleFactor * 0.5 + 0.5;

        // scale factor comes into effect as partial joint reaches 1
        colorScaleFactor = (1 - partialJoint) +
            colorScaleFactor * partialJoint;
        
        Color thisLevelColor;
        thisLevelColor.setValues( &leafColor );
        thisLevelColor.weightColor( colorScaleFactor );
        
        

        double zValue = leafPosition.mZ;

        if( zValue <= inMaxZ && zValue >= inMaxZ ) {
            // draw this joint
        
            for( int g=0; g<numLeavesPerJoint; g++ ) {

                if( Features::drawShadows ) {
                    // draw shadow
                    glColor4f( 0, 0, 0, 0.5 );
                    mLeaf.draw( &leafPosition, &currentAngle,
                                partialJoint * currentScale * radius * 1.05 );
                    }
                
                setGLColor( &thisLevelColor );

                mLeaf.draw( &leafPosition, &currentAngle,
                            // scale down further by partial fraction
                            partialJoint * currentScale * radius );

                currentAngle.add( &angleIncrement );
                }

            // finally cap this joint
            setGLColor( &thisLevelColor );
            mJointCapTexture->enable();
            glBegin( GL_QUADS ); {

                double capRadius = currentScale * radius * 0.1;
                double capZ = leafPosition.mZ;
                
                glTexCoord2f( 0, 0 );
                glVertex3d( leafPosition.mX - capRadius,
                            leafPosition.mY - capRadius, capZ );

                glTexCoord2f( 1, 0 );
                glVertex3d( leafPosition.mX + capRadius,
                            leafPosition.mY - capRadius, capZ );
                
                glTexCoord2f( 1, 1 );
                glVertex3d( leafPosition.mX + capRadius,
                            leafPosition.mY + capRadius, capZ );

                glTexCoord2f( 0, 1 );
                glVertex3d( leafPosition.mX - capRadius,
                            leafPosition.mY + capRadius, capZ );
                }
            glEnd();
            mJointCapTexture->disable();
            }
        }

    int numTerminii = thisLayerLeafTerminii.size();
    int t;
    
    if( mGrowth >= 1 ) {

        // NOTE:
        // This method of collecting all leaf terminii for the plant ASSUMES
        // that each terminus is at a unique location
        // This seems like a safe assumption, given the way leaves are
        // arranged now, but it is not safe in the general case.
        
        // If two terminii are at the same location, the terminus collection
        // would finish before collecting all terminii
        
        
        if( !mLeafTerminiiSet ) {
            // not done collecting leaf terminii for full-growth plant

            int numExisting = mLeafTerminii.size();
            char collision = false;
            
            for( int t=0; t<numTerminii && !collision; t++ ) {
                Vector3D *newTerminus =
                    *( thisLayerLeafTerminii.getElement( t ) );
                
                // make sure not the same as existing
                char same = false;
                for( int e=0; e<numExisting && !same; e++ ) {
                    Vector3D *existing = *( mLeafTerminii.getElement( e ) );

                    if( existing->equals( newTerminus ) ) {
                        same = true;
                        collision = true;
                        }
                    }

                if( !same ) {
                    // add to list of all terminii
                    mLeafTerminii.push_back( new Vector3D( newTerminus ) );
                    }                
                }

            if( collision ) {
                // we are back to drawing a layer that we've already drawn
                // before

                // so we're not gathering new leaf terminii anymore

                mLeafTerminiiSet = true;
                }
            }
        else {
        
            // don't try adding flowers if we already have more than
            // numTerminii
            // flowers
            int numTotalTerminii = mLeafTerminii.size();
            int numFlowers = mFlowerTerminusIndicies.size();
            int numFruit = mFruitTerminusIndices.size();
            
            if( numFlowers < numTotalTerminii &&
                mTimeSinceLastFlower >=
                genetics->getParameter( timeBetweenFlowers ) ) {
                // new flower

                // pick random, unflowered, unfruited terminus
            

                int numTries = 0;
                char found = false;
                int foundIndex = -1;
                while( ! found && numTries < 100 ) {
                    foundIndex =
                        globalRandomSource.getRandomBoundedInt(
                            0,
                            numTotalTerminii - 1 );
                    found = true;
                    int f;
                    for( f=0; f<numFlowers && found; f++ ) {
                        if( *( mFlowerTerminusIndicies.getElement( f ) )
                            ==
                            foundIndex ) {
                            // collision with existing flower location
                            found = false;
                            }
                        }
                    for( f=0; f<numFruit && found; f++ ) {
                        if( *( mFruitTerminusIndices.getElement( f ) )
                            ==
                            foundIndex ) {
                            // collision with existing fruit location
                            found = false;
                            }
                        }
                    numTries++;
                    }

                if( found ) {
                    mFlowerTerminusIndicies.push_back( foundIndex );
                    mFlowerStages.push_back( 0 );
                    mFlowerAngles.push_back(
                        new Angle3D(
                            0, 0,
                            globalRandomSource.getRandomBoundedDouble(
                                0, 2 * M_PI ) ) );
                    }
            
                mTimeSinceLastFlower = 0;
                }

        
            // recount, since we may have added some
            numFlowers = mFlowerTerminusIndicies.size();
            
            for( int f=0; f<numFlowers; f++ ) {
                int terminusIndex =
                    *( mFlowerTerminusIndicies.getElement( f ) );
                
                Vector3D *terminus =
                    *( mLeafTerminii.getElement( terminusIndex ) );
            
                double zValue = terminus->mZ;
                
                if( zValue <= inMaxZ && zValue >= inMaxZ ) {
                    
                    Angle3D *flowerAngle = *( mFlowerAngles.getElement( f ) );
                    
                    double flowerStage = *( mFlowerStages.getElement( f ) );
                    
                    mFlower.draw( terminus,
                                  flowerAngle, drawScale, flowerStage );
                    }
                }
            }

        // draw fruit
        int numFruit = mFruit.size();

        
        for( int f=0; f<numFruit; f++ ) {
            int terminusIndex =
                *( mFruitTerminusIndices.getElement( f ) );
                
            Vector3D *terminus =
                *( mLeafTerminii.getElement( terminusIndex ) );
            
            double zValue = terminus->mZ;
            
            if( zValue <= inMaxZ && zValue >= inMaxZ ) {
                Angle3D *fruitAngle = *( mFruitAngles.getElement( f ) );
                Fruit *thisFruit = *( mFruit.getElement( f ) );

                double fruitScale = drawScale * 0.2;
                
                thisFruit->draw( terminus,
                                 fruitAngle, fruitScale );

                if( mHighlightRipeFruit && thisFruit->isRipe() ) {

                    // make sure this is the fruit that we will harvest
                    // next
                    // (the z-range drawing can screw us
                    // up here, since we might draw fruits out-of-order)
                    // thus, the first-drawn ripe fruit is not necessarily
                    // the fruit that will be next harvested
                    Fruit *fruitNextHarvested = peekAtRipeFruit();

                    
                    if( thisFruit == fruitNextHarvested ) {
                        // this fruit will be harvested next
                                            
                        glColor4f( 1, 1, 1, 0.25 );
                        
                        // highlight brightens only
                        glBlendFunc( GL_SRC_ALPHA, GL_ONE );

                        drawBlurCircle( terminus, fruitScale );

                        // back to normal blend function
                        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

                        // only highlight one
                        mHighlightRipeFruit = false;
                        }
                    }
                }
            }
        }

    // delete this layer's terminus points
    for( t=0; t<numTerminii; t++ ) {
        delete *( thisLayerLeafTerminii.getElement( t ) );
        }
    }
Ejemplo n.º 2
0
Encoder::Encoder()
{
    zeroAngle();
}