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, ¤tAngle, currentScale * radius * 1.05 ); } // draw leaf setGLColor( &thisLevelColor ); mLeaf.draw( &leafPosition, ¤tAngle, 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( ¤tAngle ); 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, ¤tAngle, partialJoint * currentScale * radius * 1.05 ); } setGLColor( &thisLevelColor ); mLeaf.draw( &leafPosition, ¤tAngle, // 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 ) ); } }
Encoder::Encoder() { zeroAngle(); }