Ejemplo n.º 1
0
void GameResizeOrMove( NimblePixMap& map ) {
	WindowWidth = map.width();
	WindowHeight = map.height();
	// Set PanelWidth so that remaining width is mulitple of 4
	PanelWidth = PANEL_MIN_WIDTH+WindowWidth%4;
	CreateNewArea();
}
Ejemplo n.º 2
0
void ColorMatrix::buildFrom( const NimblePixMap& map ) {
	Assert(!myColors);
	int w = myWidth = map.width();
	int h = myHeight = map.height();
	myColors = new NimbleColor[myWidth*myHeight];
    for( int i=0; i<h; ++i )
		for( int j=0; j<w; ++j )
			myColors[i*w+j] = map.colorAt(j,i);
}
Ejemplo n.º 3
0
bool DrawCircle(const NimblePixMap& map, NimblePixel color, float x0, float y0, float r, bool dashed) {
    float w = map.width()-1;
    float h = map.height()-1;
    float ymin = std::numeric_limits<float>::infinity();
    float ymax = -ymin;
    ClipQuadrant(ymin, ymax, x0, y0, r, w, h);
    ClipQuadrant(ymin, ymax, w-x0, y0, r, w, h );
    ClipQuadrant(ymin, ymax, x0, h-y0, r, w, h );
    ClipQuadrant(ymin, ymax, w-x0, h-y0, r, w, h );
    if( ymin>ymax ) 
        return false;
    float y = ymin;
    float x = std::sqrt(r*r - ymin*ymin);
    float d = 2*(x*x + y*y - r*r) + (2*y+1) + (1-2*x);
    while(y <= ymax) {
        // FIXME - use lookup table indexed by quotients instead of trig
        if( !dashed || int(std::atan2(y,x)/(3.1415926535/4)*8+1)&2 ) {
            // FIXME - really cannot use octant symmetry since sub-pixel accuracy is desired
            DrawPixel(map, color, x + x0, y + y0); // Octant 1
            DrawPixel(map, color, y + x0, x + y0); // Octant 2
            DrawPixel(map, color, -x + x0, y + y0); // Octant 4
            DrawPixel(map, color, -y + x0, x + y0); // Octant 3
            DrawPixel(map, color, -x + x0, -y + y0); // Octant 5
            DrawPixel(map, color, -y + x0, -x + y0); // Octant 6
            DrawPixel(map, color, x + x0, -y + y0); // Octant 7
            DrawPixel(map, color, y + x0, -x + y0); // Octant 8
        }
        ++y;
        if( d<=0 ) {
            d += 4*y + 2;
        } else {
            --x;
            d += 4*(y-x) + 2;
        }
    }
    return true;
}
Ejemplo n.º 4
0
static void DrawPixel( const NimblePixMap& map, NimblePixel color, float xf, float yf ) {
    if( 0<=xf && xf<map.width() && 0<=yf && yf<map.height() ) {
        *(NimblePixel*)map.at(int(xf),int(yf)) = color;
    }
}
//! Draw the potential field on the given map
void DrawPotentialFieldBilinear(const NimblePixMap& map) {
    using namespace Universe;
    int w = map.width();
    int h = map.height();
    size_t n = NParticle;
    float cutoffRadius = 8*ViewScale*PATCH_SIZE;
    // FIXME - deal with pixels near boundary that do not lie in a complete patch.
    for(int i0=0; i0<h; i0+=PATCH_SIZE) {
        int iSize = std::min(PATCH_SIZE,h-i0);
        for(int j0=0; j0<w; j0+=PATCH_SIZE) {
            float a00 = 0, a01 = 0, a10 = 0, a11 = 0;
            float y0 = ViewOffsetY + ViewScale*i0;
            float x0 = ViewOffsetX + ViewScale*j0;
            float y1 = ViewOffsetY + ViewScale*(i0 + PATCH_SIZE);
            float x1 = ViewOffsetX + ViewScale*(j0 + PATCH_SIZE);
            float xm = 0.5f*(x0+x1);
            float ym = 0.5f*(y0+y1);
            size_t nearN = 0;
            for(size_t k=0; k<n; ++k) {
                float sx = Sx[k];
                float sy = Sy[k];
                if( std::sqrt(Dist2(sx,sy,xm,ym)) <= cutoffRadius ) {
                    // Use particle exactly
                    NearX[nearN] = sx;
                    NearY[nearN] = sy;
                    NearCharge[nearN] = Charge[k];
                    ++nearN;
                } else {
                    // Use bilinear interpolation
                    a00 += PotentialAt(k, x0, y0);
                    a01 += PotentialAt(k, x0, y1);
                    a10 += PotentialAt(k, x1, y0);
                    a11 += PotentialAt(k, x1, y1);
                }
            }
            float x[PATCH_SIZE], p[PATCH_SIZE];
            for(int j=0; j<PATCH_SIZE; ++j) {
                x[j] = ViewOffsetX + ViewScale*(j0+j);
            }
            // Work one row at a time to optimize cache usage
            // j-loops really only have to do jSize iterations, but do PATCH_SIZE anyway on theory
            // that it avoids remainder loops.
            int jSize = std::min(PATCH_SIZE, w-j0);
            for(int i=0; i<iSize; ++i) {
                // Set potential accumulator to bilinear interpolation values
                float fy = i*(1.0f/PATCH_SIZE);
                float b0 = a00*(1-fy) + a01*fy;
                float b1 = ((a10*(1-fy) + a11*fy) - b0)*(1.0f/PATCH_SIZE);
                for(int j=0; j<PATCH_SIZE; ++j) {
                    float fx = j*(1.0f/PATCH_SIZE);
                    p[j] = b0 + b1*j; 
                }
                // Do loop over particles as middle loop to hide latency of summation.
                float y = ViewOffsetY + ViewScale*(i0+i);
                for(size_t k=0; k<nearN; ++k) {
                    float dy = NearY[k]-y;
                    float q = NearCharge[k];
                    // Inner loop. 
                    for(int j=0; j<PATCH_SIZE; ++j) {
                        float dx = NearX[k]-x[j];
                        float r = std::sqrt(dx*dx+dy*dy);
                        p[j] += q/r;
                    }
                }
                DrawPotentialRow((NimblePixel*)map.at(j0, i0+i), p, jSize);
            }
        }
    }
}
Ejemplo n.º 6
0
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();
}