void ColorFuncMakeClut( NimblePixel clut[SAMPLE_CLUT_SIZE], int rockType, const NimblePixMap& map, float showGeology, float showSeismic, ColorFunc colorFunc ) { // Note: rockType==RockTypeMax is used for the seismogram coloring. Assert(rockType<=RockTypeMax); Assert(0<=showGeology && showGeology<=1); Assert(0<=showSeismic && showSeismic<=1); int w = GuideColors.width(); int h = GuideColors.height(); Assert(w%2==1); float scale = showSeismic*float(w/2); if( colorFunc==CF_Log ) scale /= asinhf(LogScaleStretch); for( int j=0; j<=SAMPLE_CLUT_SIZE/2; ++j ) { // u is normalized amplitude in range [-1,1] float u = j*(2.0f/SAMPLE_CLUT_SIZE); float v; switch( colorFunc ) { case CF_SignOnly: v = u==0 ? 0 : 2.0f/3; break; case CF_Log: v = asinhf(u*LogScaleStretch); break; case CF_Linear: v = u; break; } TransferFunc[SAMPLE_CLUT_SIZE/2+j] = v*scale; TransferFunc[SAMPLE_CLUT_SIZE/2-j] = -v*scale; } // Get rock-independent color. The "-2" is there instead of "-1" because "-1" // is for an unused "light" color scale as opposed to the "dark" scale at "-2". const NimbleColor* colorScale0 = GuideColors[h-2]+w/2; // Get rock-dependent color const NimbleColor* colorScale1 = GuideColors[rockType]+w/2; for( int j=0; j<SAMPLE_CLUT_SIZE; ++j ) { int k = int(TransferFunc[j]); float residue = TransferFunc[j]-k; Assert( k<GuideColors.width() ); NimbleColor c0 = colorScale0[k]; NimbleColor c1 = colorScale1[k]; if( residue>0 ) { c0.mix(colorScale0[k+1],residue); c1.mix(colorScale1[k+1],residue); } if( residue<0 ) { c0.mix(colorScale0[k-1],-residue); c1.mix(colorScale1[k-1],-residue); } c0.mix(c1,showGeology); clut[j] = map.pixel(c0); } }
void GameUpdateDraw( NimblePixMap& map, NimbleRequest request ) { #if WRITING_DOCUMENTATION new(&TheMap) NimblePixMap( map ); #endif /* WRITING_DOCUMENTATION */ WavefieldRect = NimbleRect(PanelWidth,map.height()/2,map.width(),map.height()); NimblePixMap subsurface(map,WavefieldRect); NimblePixMap seismogramClip( map,NimbleRect(PanelWidth,0,map.width(),map.height()/2) ); if( request & NimbleUpdate ) { ShowGeology.update(); ShowSeismic.update(); } const NimbleRequest pausedRequest = IsPaused ? request-NimbleUpdate : request; SeismogramUpdateDraw( seismogramClip, pausedRequest&NimbleUpdate, TheColorFunc, IsAutoGainOn ); WavefieldFunctor wf(subsurface, pausedRequest); SeismogramFunctor sf( seismogramClip, pausedRequest&NimbleDraw ); ReservoirFunctor rf( pausedRequest ); #if PARALLEL tbb::parallel_invoke( wf, sf, rf ); #else wf(); sf(); rf(); #endif if( pausedRequest & NimbleUpdate ) { DrillBit.update(); UpdateDuckAndRig(); } if( request & NimbleDraw ) { ClickableSetEnd = ClickableSet; const int wavefieldWidth = map.width()-PanelWidth; Assert(wavefieldWidth%4==0); const int wavefieldHeight = map.height()/2; ReservoirDrawHoles( subsurface ); if( DrillY>0 ) DrillBit.drawOn( subsurface, RigX-DrillBit.width()/2, DrillY-5 ); if( ShowReservoir ) ReservoirDraw( subsurface ); NimblePixMap spriteClip( map, NimbleRect( PanelWidth, 0, map.width(), map.height() ));\ NimblePixel greenPixel = map.pixel( NimbleColor( 0, NimbleColor::FULL, 0 )); NimblePixel redPixel = map.pixel( NimbleColor( NimbleColor::FULL, 0, 0 )); const int lineHeight = map.height()/2-1; if( CultureBeginX<CultureEndX ) { spriteClip.draw( NimbleRect( 0, lineHeight, CultureBeginX, lineHeight+1 ), greenPixel ); spriteClip.draw( NimbleRect( CultureBeginX, lineHeight-1, CultureEndX, lineHeight+2 ), redPixel ); spriteClip.draw( NimbleRect( CultureEndX, lineHeight, spriteClip.width(), lineHeight+1 ), greenPixel ); Culture.drawOn( spriteClip, CultureBeginX+(CultureEndX-CultureBeginX)/2-Culture.width()/2, map.height()/2-Culture.height() ); } else { spriteClip.draw( NimbleRect( 0, lineHeight, spriteClip.width(), lineHeight+1 ), greenPixel ); } OilRig->drawOn( spriteClip, RigX-OilRig->width()/2, OilRigVerticalOffset ); if( DuckGoingLeft ) DuckLeft.drawOn( spriteClip, DuckX-50, map.height()/2-DuckLeft.height()+12 ); else DuckRight.drawOn( spriteClip, DuckX-(DuckRight.width()-50), map.height()/2-DuckLeft.height()+12 ); NimblePixMap panelClip( map, NimbleRect( 0, 0, PanelWidth, map.height() )); PanelBackground.drawOn( panelClip ); int cashMeterY = map.height()- 50 -CashMeter.height(); int levelMeterY = cashMeterY - 10 - LevelMeter.height(); // The Min is there so that if there is room, the green line artistically lines up // with the top of the fluid meters. int fluidMeterY = Min(levelMeterY - 10 - WaterMeter.height(), map.height()/2 ); if( ScoreState.isDisplayingScore() ) { LevelMeter.drawOn( map, PanelWidth/2-LevelMeter.width()/2, levelMeterY ); CashMeter.drawOn( map, PanelWidth/2-CashMeter.width()/2, cashMeterY ); } int meterMarginX = (PanelWidth-WaterMeter.width()-OilMeter.width()-GasMeter.width())/4; WaterMeter.drawOn( map, meterMarginX, fluidMeterY ); OilMeter.drawOn( map, PanelWidth/2-OilMeter.width()/2, fluidMeterY ); GasMeter.drawOn( map, PanelWidth-meterMarginX-GasMeter.width(), fluidMeterY ); if( VisibleDialog ) { if( VisibleDialog==&TheAboutTheAuthorDialog || VisibleDialog==&TheLevelContinueDialog ) // Center it on screen VisibleDialog->drawOn( map, map.width()/2-VisibleDialog->width()/2, map.height()/2-VisibleDialog->height()/2 ); else if( VisibleDialog==&TheKeyboardHelpDialog ) // Put in upper right corner VisibleDialog->drawOn( map, map.width()*.95f-VisibleDialog->width(), map.height()*.05f ); else // Put it in upper left portion of seismogram VisibleDialog->drawOn( map, PanelWidth+24, 24 ); } int tabTop1 = 50; int tabTop2 = tabTop1+2*TheFont.height(); int tabLeft1 = PanelWidth/8; int tabLeft2 = PanelWidth*5/8; int airGunTop = tabTop2+2*TheFont.height();; AirgunMeter.drawOn( map, PanelWidth/2-AirgunMeter.width()/2, airGunTop ); if( ShowFrameRate ) { FrameRateMeter.setValue( EstimateFrameRate() ); FrameRateMeter.drawOn( map, PanelWidth/2-FrameRateMeter.width()/2, fluidMeterY-FrameRateMeter.height()-15 ); } const int tabSpacing = PanelWidth/4; DrawClickable( TheFileMenu, map, tabLeft1, tabTop1 ); DrawClickable( TheHelpMenu, map, tabLeft2, tabTop1 ); // The "isTabbed" tests below do some ad-hoc occlusion testing. if( TheFileMenu.isTabbed() ) DrawClickable( TheModelMenu, map, tabLeft1, tabTop2 ); if( TheFileMenu.isTabbed() && TheHelpMenu.isTabbed() ) DrawClickable( TheViewMenu, map, tabLeft2, tabTop2 ); } ScoreState.update(); }