Exemple #1
0
/**
 * Renders the upper symbology (compass, map scale, flight mode icon,
 * thermal band, final glide bar and gps status)
 * @param canvas The drawing canvas
 * @param rc The area to draw in
 */
void
MapWindow::RenderSymbology_upper(Canvas &canvas, const RECT &rc)
{
  const NMEA_INFO &data = Basic();

  // overlays
  DrawCDI();

  canvas.select(Fonts::Map);
  DrawMapScale(canvas, rc);
  DrawMapScale2(canvas, rc);
  DrawCompass(canvas, rc);

  // JMW Experimental only! EXPERIMENTAL
#if 0
  if (EnableAuxiliaryInfo)
    DrawHorizon(canvas, rc);
#endif

  DrawFlightMode(canvas, rc);
  DrawThermalBand(canvas, rc);
  DrawFinalGlide(canvas,rc);
  DrawGPSStatus(canvas, rc, data.gps);
}
Exemple #2
0
int MapWindow::SharedTopView(LKSurface& Surface, DiagrammStruct* psDia , double fAS_Bearing, double fWP_Bearing)
{
    int iOldDisplayOrientation =  DisplayOrientation;
    DiagrammStruct m_Dia =	*psDia;
    const RECT& rct = m_Dia.rc;

    unsigned short getsideviewpage=GetSideviewPage();
    LKASSERT(getsideviewpage<NUMBER_OF_SHARED_MULTIMAPS);
    LKASSERT(Current_Multimap_SizeY!=SIZE0);

    DisplayOrientation = GetMMNorthUp(getsideviewpage);

    switch(GetMMNorthUp(getsideviewpage))
    {
    case TRACKUP:
        break;

    case NORTHUP:
    default:
        m_Dia.fXMin = -m_Dia.fXMax;
        break;
    }

    double fOldScale  =  zoom.Scale();
    const auto hfOld = Surface.SelectObject(LK8PanelUnitFont);

    if(zoom.AutoZoom())
        zoom.AutoZoom(false);
    double fFact = 1.25 ;
#ifdef INIT_CASE


    switch(ScreenSize) {

    case ss800x480:
        fFact=0.750;
        break;
    case ss640x480:
        fFact=0.938;
        break;
    case ss480x272:
        fFact=0.708;
        break;
    case ss400x240:
        fFact=0.750;
        break;
    case ss320x240:
        fFact=0.938;
        break;
    case ss480x800:
        fFact=1.250;
        break;
    case ss480x640:
        fFact=1.250;
        break;
    case ss272x480:
        fFact=1.250;
        break;
    case ss240x400:
        fFact=1.250;
        break;
    case ss240x320:
        fFact=1.250;
        break;
    default:
        fFact=1.000;
        break;
    }
#endif


    if((ScreenSizeX > 0) && (ScreenSizeY > 0))
    {
        if(ScreenSizeX > ScreenSizeY)
            fFact = (double)ScreenSizeY/(double)ScreenSizeX * 1.250;

    }
    PanLatitude  = DrawInfo.Latitude;
    PanLongitude = DrawInfo.Longitude;

    switch(GetMMNorthUp(getsideviewpage))
    {
    case TRACKUP:
        DisplayAngle = AngleLimit360(fAS_Bearing  +270.0);
        DisplayAircraftAngle = AngleLimit360(fWP_Bearing);
        break;

    case NORTHUP:
    default:
        DisplayAngle = 0;
        if( getsideviewpage == IM_HEADING || getsideviewpage==IM_VISUALGLIDE)
            DisplayAircraftAngle = AngleLimit360(fAS_Bearing);
        else
            DisplayAircraftAngle = AngleLimit360(DrawInfo.TrackBearing);
        break;
    }

    int iOldLocator = EnableThermalLocator;
    EnableThermalLocator =0;

    /*******/
#warning "wrong place for do that, always bad idea to change layout inside drawing fonctions !"
    MapWindow::ChangeDrawRect(rct);       // set new area for terrain and topology
    /*******/

    zoom.RequestedScale((m_Dia.fXMax -m_Dia.fXMin)  * fFact *  (DISTANCEMODIFY)/10.0f);

    POINT Orig           =  { CalcDistanceCoordinat(0.0,  (DiagrammStruct*) &m_Dia),(rct.bottom-rct.top)/2};
    POINT Orig_Aircraft= {0,0};

    zoom.ModifyMapScale();
    zoom.UpdateMapScale();

    const ScreenProjection _Proj = CalculateScreenPositions( Orig, rct, &Orig_Aircraft);

    CalculateScreenPositionsAirspace(rct, _Proj);

    bool terrainpainted=false;

    if (IsMultimapTerrain() &&  DerivedDrawInfo.TerrainValid && RasterTerrain::isTerrainLoaded() ) {
        LKTextBlack=false;
        BlackScreen=false;
        LockTerrainDataGraphics();
        DrawTerrain(Surface, rct, _Proj, GetAzimuth(), 40.0);
        UnlockTerrainDataGraphics();
        terrainpainted=true;
    } else {
        // We fill up the background wity chosen empty map color
        Surface.FillRect(&rct, hInvBackgroundBrush[BgMapColor]);
        // We force LK painting black values on screen depending on the background color in use
        // blackscreen would force everything to be painted white, instead
        LKTextBlack=BgMapColorTextBlack[BgMapColor];
        if (BgMapColor>6 ) BlackScreen=true;
        else BlackScreen=false;
    }

    ResetLabelDeclutter();

    // We reduce screen cluttering for some cases..
    short olddecluttermode=DeclutterMode;
    if (Current_Multimap_SizeY==SIZE4) goto _nomoredeclutter;
    if (Current_Multimap_SizeY<SIZE3) {
        DeclutterMode+=2;
    } else {
        if (Current_Multimap_SizeY==SIZE3)
            DeclutterMode++;
    }
    if (DeclutterMode>dmVeryHigh) DeclutterMode=dmVeryHigh;

_nomoredeclutter:

    if (IsMultimapTopology()) {
        // Do not print topology labels, to be used with another config later!
        // SaturateLabelDeclutter();
        DrawTopology(Surface, rct, _Proj);
    } else {
        // No topology is desired, but terrain requires water areas nevertheless
        if (terrainpainted) {
            DrawTopology(Surface, rct, _Proj, true); // water only!
        }
    }


    if (IsMultimapAirspace()) {
        DrawAirSpace(Surface, rct, _Proj);   // full screen, to hide clipping effect on low border
    }

    if (Flags_DrawTask && MapSpaceMode!=MSM_MAPASP && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) {
        DrawTaskAAT(Surface, rct);
        DrawTask(Surface, rct, _Proj, Orig_Aircraft);
    }

    if (IsMultimapWaypoints()) {
        DrawWaypointsNew(Surface,rct);
    }
    if (Flags_DrawFAI)
        DrawFAIOptimizer(Surface, rct, _Proj, Orig_Aircraft);

    DeclutterMode=olddecluttermode; // set it back correctly

    /* THIS STUFF DOES NOT WORK IN SHARED MAPS, YET
       NEED FIXING LatLon2Screen for shared maps using Sideview
       #ifdef GTL2
       if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) &&
    DerivedDrawInfo.TerrainValid)
    DrawTerrainAbove(hdc, rct);
       #endif
     */


    //
    // Stuff for MAPTRK only (M1)
    if (MapSpaceMode==MSM_MAPTRK) {
        if(IsMultimapTerrain() || IsMultimapTopology() ) {
            if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid)
                DrawGlideThroughTerrain(Surface, rct, _Proj);
        }
        if (extGPSCONNECT)
            DrawBearing(Surface, rct, _Proj);
        // Wind arrow
        if (IsMultimapOverlaysGauges())
            DrawWindAtAircraft2(Surface, Orig_Aircraft, rct);
    }

    if (MapSpaceMode==MSM_MAPWPT) {
        if (extGPSCONNECT)
            DrawBearing(Surface, rct, _Proj);
    }

    switch(GetMMNorthUp(getsideviewpage)) {
    case NORTHUP:
    default:
        DrawCompass( Surface,  rct, 0);
        break;
    case TRACKUP:
        if(getsideviewpage ==  IM_HEADING || getsideviewpage == IM_VISUALGLIDE)
            DrawCompass( Surface,  rct, DrawInfo.TrackBearing-90.0);
        else
            DrawCompass( Surface,  rct, DisplayAngle);
        break;
    }


    /****************************************************************************************************
     * draw vertical line
     ****************************************************************************************************/
    POINT line[2];
    line[0].x = rct.left;
    line[0].y = Orig_Aircraft.y-1;
    line[1].x = rct.right;
    line[1].y = line[0].y;

    switch(GetMMNorthUp(getsideviewpage))
    {
    case TRACKUP:
        // Are we are not topview fullscreen?
        if (Current_Multimap_SizeY<SIZE4 && !(MapSpaceMode==MSM_VISUALGLIDE)) {
            Surface.DrawDashLine(NIBLSCALE(1), line[0], line[1],  Sideview_TextColor, rct);
        } else {
            if (TrackBar) {
                DrawHeadUpLine(Surface, Orig, rct, psDia->fXMin ,psDia->fXMax);
                if (ISGAAIRCRAFT) DrawFuturePos(Surface, Orig, rct, true);
            }
        }
        break;

    case NORTHUP:
    default:
        if (TrackBar) {
            DrawHeadUpLine(Surface, Orig, rct, psDia->fXMin ,psDia->fXMax);
            if (ISGAAIRCRAFT) DrawFuturePos(Surface, Orig, rct, true);
        }
        break;
    }
    DrawAircraft(Surface, Orig_Aircraft);

    // M3 has sideview always on, so wont apply here, and no need to check
    if (Current_Multimap_SizeY==SIZE4) {
        DrawMapScale(Surface,rct,0);
    }

    MapWindow::zoom.RequestedScale(fOldScale);
    EnableThermalLocator = iOldLocator;
    DisplayOrientation = iOldDisplayOrientation;
    Surface.SelectObject(hfOld);
    return 0;

}
void
MapWindow::Render(Canvas &canvas, const PixelRect &rc)
{ 
  const NMEAInfo &basic = Basic();

  // reset label over-write preventer
  label_block.reset();

  render_projection = visible_projection;

  if (!render_projection.IsValid()) {
    canvas.ClearWhite();
    return;
  }

  // Calculate screen position of the aircraft
  RasterPoint aircraft_pos{0,0};
  if (basic.location_available)
      aircraft_pos = render_projection.GeoToScreen(basic.location);

  // Render terrain, groundline and topography
  draw_sw.Mark("RenderTerrain");
  RenderTerrain(canvas);

  draw_sw.Mark("RenderTopography");
  RenderTopography(canvas);

  draw_sw.Mark("RenderFinalGlideShading");
  RenderFinalGlideShading(canvas);

  // Render track bearing (ground track)
  draw_sw.Mark("DrawTrackBearing");
  DrawTrackBearing(canvas, aircraft_pos);

  // Render airspace
  draw_sw.Mark("RenderAirspace");
  RenderAirspace(canvas);

  // Render task, waypoints
  draw_sw.Mark("DrawContest");
  DrawContest(canvas);

  draw_sw.Mark("DrawTask");
  DrawTask(canvas);

  draw_sw.Mark("DrawWaypoints");
  DrawWaypoints(canvas);

  draw_sw.Mark("DrawNOAAStations");
  RenderNOAAStations(canvas);

  draw_sw.Mark("RenderMisc1");
  // Render weather/terrain max/min values
  DrawTaskOffTrackIndicator(canvas);

  // Render the snail trail
  if (basic.location_available)
    RenderTrail(canvas, aircraft_pos);

  RenderMarkers(canvas);

  // Render estimate of thermal location
  DrawThermalEstimate(canvas);

  // Render topography on top of airspace, to keep the text readable
  draw_sw.Mark("RenderTopographyLabels");
  RenderTopographyLabels(canvas);

  // Render glide through terrain range
  draw_sw.Mark("RenderGlide");
  RenderGlide(canvas);

  draw_sw.Mark("RenderMisc2");

  DrawBestCruiseTrack(canvas, aircraft_pos);

  airspace_renderer.DrawIntersections(canvas, render_projection);

  // Draw wind vector at aircraft
  if (basic.location_available)
    DrawWind(canvas, aircraft_pos, rc);

  // Draw traffic

#ifdef HAVE_SKYLINES_TRACKING_HANDLER
  DrawSkyLinesTraffic(canvas);
#endif

  DrawTeammate(canvas);

  if (basic.location_available)
    DrawFLARMTraffic(canvas, aircraft_pos);

  // Finally, draw you!
  if (basic.location_available)
    AircraftRenderer::Draw(canvas, GetMapSettings(), look.aircraft,
                           basic.attitude.heading - render_projection.GetScreenAngle(),
                           aircraft_pos);

  // Render compass
  DrawCompass(canvas, rc);
}
Exemple #4
0
void MapWindow::DrawThread ()
{
  while ((!ProgramStarted) || (!Initialised)) {
	Poco::Thread::sleep(50);
  }

  #if TRACETHREAD
  StartupStore(_T("##############  DRAW threadid=%d\n"),GetCurrentThreadId());
  #endif

  #if TESTBENCH
  StartupStore(_T("... DrawThread START%s"),NEWLINE);
  #endif

  // THREADRUNNING = FALSE;
  THREADEXIT = FALSE;

  bool lastdrawwasbitblitted=false;

  //
  // Big LOOP
  //

  while (!CLOSETHREAD)
  {
	if(drawTriggerEvent.tryWait(5000))
	if (CLOSETHREAD) break; // drop out without drawing

	if ((!THREADRUNNING) || (!GlobalRunning)) {
        Poco::Thread::sleep(50);
		continue;
	}
    drawTriggerEvent.reset();

#ifdef HAVE_CPU_FREQUENCY
    const ScopeLockCPU cpu;
#endif

    ScopeLock Lock(Surface_Mutex);

	// Until MapDirty is set true again, we shall only repaint the screen. No Render, no calculations, no updates.
	// This is intended for very fast immediate screen refresh.
	//
	// MapDirty is set true by:
	//   - TriggerRedraws()  in calculations thread
	//   - RefreshMap()      in drawthread generally
	//


	extern POINT startScreen, targetScreen;
	extern bool OnFastPanning;
	// While we are moving in bitblt mode, ignore RefreshMap requests from LK
	// unless a timeout was triggered by MapWndProc itself.
	if (OnFastPanning) {
		MapDirty=false;
	}

	// We must check if we are on FastPanning, because we may be in pan mode even while
	// the menu buttons are active and we are using them, accessing other functions.
	// In that case, without checking OnFastPanning, we would fall back here and repaint
	// with bitblt everytime, while instead we were asked a simple fastrefresh!
	//
	// Notice: we could be !MapDirty without OnFastPanning, of course!
	//
	if (!MapDirty && !ForceRenderMap && OnFastPanning && !first_run) {

		if (!mode.Is(Mode::MODE_TARGET_PAN) && mode.Is(Mode::MODE_PAN)) {

			const int fromX=startScreen.x-targetScreen.x;
			const int fromY=startScreen.y-targetScreen.y;

            PixelRect  clipSourceArea(MapRect); // Source Rectangle
            RasterPoint clipDestPoint(clipSourceArea.GetOrigin()); // destination origin position
            PixelRect  WhiteRectV(MapRect); // vertical White band (left or right)
            PixelRect  WhiteRectH(MapRect); // horizontal White band (top or bottom)

            if (fromX<0) {
                clipSourceArea.right += fromX; // negative fromX
                clipDestPoint.x -= fromX;
                WhiteRectV.right = WhiteRectV.left - fromX;
                WhiteRectH.left = WhiteRectV.right;
            } else {
                clipSourceArea.left += fromX;
                WhiteRectV.left = WhiteRectV.right - fromX;
                WhiteRectH.right = WhiteRectV.left;
            }

            if (fromY<0) {
                clipSourceArea.bottom += fromY; // negative fromX
                clipDestPoint.y -= fromY;
                WhiteRectH.bottom = WhiteRectH.top - fromY;
            } else {
                clipSourceArea.top += fromY;
                WhiteRectH.top = WhiteRectH.bottom - fromY;
            }

#ifndef USE_GDI
            ScopeLock Lock(BackBuffer_Mutex);
#endif

            BackBufferSurface.Whiteness(WhiteRectV.left, WhiteRectV.top, WhiteRectV.GetSize().cx, WhiteRectV.GetSize().cy);
            BackBufferSurface.Whiteness(WhiteRectH.left, WhiteRectH.top, WhiteRectH.GetSize().cx, WhiteRectH.GetSize().cy);
            BackBufferSurface.Copy(clipDestPoint.x,clipDestPoint.y,
                clipSourceArea.GetSize().cx,
                clipSourceArea.GetSize().cy,
                DrawSurface,
                clipSourceArea.left,clipSourceArea.top);


			const RasterPoint centerscreen = { ScreenSizeX/2, ScreenSizeY/2 };
			DrawMapScale(BackBufferSurface,MapRect,false);
			DrawCrossHairs(BackBufferSurface, centerscreen, MapRect);
			lastdrawwasbitblitted=true;
		} else {
			// THIS IS NOT GOING TO HAPPEN!
			//
			// The map was not dirty, and we are not in fastpanning mode.
			// FastRefresh!  We simply redraw old bitmap.
			//
#ifndef USE_GDI
            ScopeLock Lock(BackBuffer_Mutex);
#endif
            DrawSurface.CopyTo(BackBufferSurface);

			lastdrawwasbitblitted=true;
		}

		// Now we can clear the flag. If it was off already, no problems.
//		OnFastPanning=false;
        MainWindow.Redraw(MapRect);
		continue;

	} else {
		//
		// Else the map wasy dirty, and we must render it..
		// Notice: if we were fastpanning, than the map could not be dirty.
		//

		#if 1 // --------------------- EXPERIMENTAL, CHECK ZOOM IS WORKING IN PNA
		static unsigned lasthere=0;
		// Only for special case: PAN mode, map not dirty (including requests for zooms!)
		// not in the ForceRenderMap run and last time was a real rendering. THEN, at these conditions,
		// we simply redraw old bitmap, for the scope of accelerating touch response.
		// In fact, if we are panning the map while rendering, there would be an annoying delay.
		// This is using lastdrawwasbitblitted
		if (INPAN && !MapDirty && !lastdrawwasbitblitted && !ForceRenderMap && !first_run) {
			// In any case, after 5 seconds redraw all
			if ( (LKHearthBeats-8) >lasthere ) {
				lasthere=LKHearthBeats;
				goto _dontbitblt;
			}
#ifndef USE_GDI
            ScopeLock Lock(BackBuffer_Mutex);
#endif
            DrawSurface.CopyTo(BackBufferSurface);

			const RasterPoint centerscreen = { ScreenSizeX/2, ScreenSizeY/2 };
			DrawMapScale(BackBufferSurface,MapRect,false);
			DrawCrossHairs(BackBufferSurface, centerscreen, MapRect);
            MainWindow.Redraw(MapRect);
			continue;
		}
		#endif // --------------------------
_dontbitblt:
		MapDirty = false;
		PanRefreshed=true;
	} // MapDirty

	lastdrawwasbitblitted=false;
	MapWindow::UpdateInfo(&GPS_INFO, &CALCULATED_INFO);
	RenderMapWindow(DrawSurface, MapRect);

    {
#ifndef USE_GDI
        ScopeLock Lock(BackBuffer_Mutex);
#endif
        if (!ForceRenderMap && !first_run) {
            DrawSurface.CopyTo(BackBufferSurface);
        }

        // Draw cross sight for pan mode, in the screen center,
        // after a full repaint while not fastpanning
        if (mode.AnyPan() && !mode.Is(Mode::MODE_TARGET_PAN) && !OnFastPanning) {
            POINT centerscreen;
            centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2;
            DrawMapScale(BackBufferSurface,MapRect,false);
            DrawCompass(BackBufferSurface, MapRect, DisplayAngle);
            DrawCrossHairs(BackBufferSurface, centerscreen, MapRect);
        }
    }

	UpdateTimeStats(false);

	// we do caching after screen update, to minimise perceived delay
	// UpdateCaches is updating topology bounds when either forced (only here)
	// or because MapWindow::ForceVisibilityScan  is set true.
    const ScreenProjection _Proj;
	UpdateCaches(_Proj, first_run);
	first_run=false;

	ForceRenderMap = false;

	if (ProgramStarted==psInitDone) {
		ProgramStarted = psFirstDrawDone;
	}
    MainWindow.Redraw(MapRect);

  } // Big LOOP

  #if TESTBENCH
  StartupStore(_T("... Thread_Draw terminated\n"));
  #endif
  THREADEXIT = TRUE;

}
void MapWindow::RenderMapWindowBg(LKSurface& Surface, const RECT& rc) {

    if ( (LKSurface::AlphaBlendSupported() && BarOpacity < 100) || mode.AnyPan() ) {
        RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY};
        MapWindow::ChangeDrawRect(newRect);
    } else {
        RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY - BottomSize - (ScreenSizeY-MapRect.bottom)-1};
        MapWindow::ChangeDrawRect(newRect);
    }

    if (QUICKDRAW) {
        goto _skip_calcs;
    }


    // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed
    // updating of visible landables, for example. The nearest pages do this separately, with their own sorting.
    // Basically we assume -like for nearest- that values will not change that much in the multicalc split time.
    // Target and tasks are recalculated in real time in any case. Nearest too. 
    LKCalculateWaypointReachable(false);

_skip_calcs:

    if (PGZoomTrigger) {
        if (!mode.Is(Mode::MODE_PANORAMA)) {
            mode.Special(Mode::MODE_SPECIAL_PANORAMA, true);
            LastZoomTrigger = DrawInfo.Time;

            Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s
            LKSound(TEXT("LK_TONEUP.WAV"));
        } else {
            // previously called, see if time has passed
            if (DrawInfo.Time > (LastZoomTrigger + 20.0)) {
                // time has passed, lets go back
                LastZoomTrigger = 0; // just for safety
                mode.Special(Mode::MODE_SPECIAL_PANORAMA, false);
                PGZoomTrigger = false;
                Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM
                LKSound(TEXT("LK_TONEDOWN.WAV"));
            }
        }
    }

    // 
    // "Checkpoint Charlie"
    // This is were we process stuff for anything else but main map.
    // We let the calculations run also for MapSpace modes.
    // But for multimaps, we can also draw some more stuff..
    // We are also sent back here from next code, when we detect that
    // the MapSpace mode has changed from MAP to something else while we
    // were rendering.
    //
QuickRedraw:
    //
    if (DONTDRAWTHEMAP) {
        const bool isMultimap = IsMultiMapShared(); // DrawMapSpace can change "MapSpaceMode", get this before. 
        DrawMapSpace(Surface, rc);
        // Is this a "shared map" environment? 
        if (isMultimap) {
            // Shared map, of course not MSN_MAP, since dontdrawthemap was checked
            //
            if (IsMultimapOverlaysGauges()) {
                RenderOverlayGauges(Surface, rc);
            }
            if (IsMultimapOverlaysText()) {
                DrawLook8000(Surface, rc);
            }

        } else {
            // Not in map painting environment 
            // ex. nearest pages, but also MAPRADAR..
        }

        // 
        DrawBottomBar(Surface, rc);
#ifdef DRAWDEBUG
        DrawDebug(hdc, rc);
#endif
        // no need to do SelectObject as at the bottom of function
        return;
    }

    POINT Orig, Orig_Aircraft;
    CalculateOrigin(rc, &Orig);
    const ScreenProjection _Proj = CalculateScreenPositions(Orig, rc, &Orig_Aircraft);

    // When no terrain is painted, set a background0
    // Remember that in this case we have plenty of cpu time to spend for best result
    if (!IsMultimapTerrain() || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded()) {
        // We force LK painting black values on screen depending on the background color in use
        // TODO make it an array once settled
        // blackscreen would force everything to be painted white, instead
        LKTextBlack = BgMapColorTextBlack[BgMapColor];
        if (BgMapColor > 6) BlackScreen = true;
        else BlackScreen = false;
    } else {
        LKTextBlack = false;
        BlackScreen = false;
    }

    // Logic of DONTDRAWTHEMAP is the following:
    // We are rendering the screen page here. If we are here, we passed Checkpoint Charlie.
    // So we were, at charlie, in MSM_MAP: preparing the main map stuff.
    // If we detect that MapSpace has CHANGED while we were doing our job here,
    // it means that the user has clicked meanwhile. He desires another page, so let's
    // reset our intentions and go back to beginning, or nearby..
    // We have a new job to do, for another MapSpace, no more MAP.
    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    bool terrainpainted = false;

    if ((IsMultimapTerrain() && (DerivedDrawInfo.TerrainValid)
            && RasterTerrain::isTerrainLoaded())
            ) {
        // sunelevation is never used, it is still a todo in Terrain
        double sunelevation = 40.0;
        double sunazimuth = GetAzimuth();

        LockTerrainDataGraphics();
        if (DONTDRAWTHEMAP) { // 100318
            UnlockTerrainDataGraphics();
            goto QuickRedraw;
        }
        
        if(DrawTerrain(Surface, DrawRect, _Proj, sunazimuth, sunelevation)) {
            terrainpainted = true;
        }
        
        if (DONTDRAWTHEMAP) {
            UnlockTerrainDataGraphics();
            goto QuickRedraw;
        }
        if (!QUICKDRAW) {
            // SHADED terrain unreachable, aka glide amoeba. This is not the outlined perimeter!
#ifdef GTL2
            if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) &&
                    DerivedDrawInfo.TerrainValid) {
#else
            if ((FinalGlideTerrain == 2) && DerivedDrawInfo.TerrainValid) {
#endif
                DrawTerrainAbove(Surface, DrawRect);
            }
        }
        UnlockTerrainDataGraphics();
    }

    //
    // REMINDER: WE ARE IN MAIN MAP HERE: MSM_MAP ONLY, OR PANNING MODE!
    // MAPSPACEMODE CAN STILL CHANGE, DUE TO USER INPUT. BUT WE GOT HERE IN
    // EITHER PAN OR MSM_MAP.
    //

    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    if(!terrainpainted) {
        // fill background..
        Surface.FillRect(&rc, hInvBackgroundBrush[BgMapColor]);
    }
        
        
    if (IsMultimapTopology()) {
        DrawTopology(Surface, DrawRect, _Proj);
    } else {
        // If no topology wanted, but terrain painted, we paint only water stuff
        if (terrainpainted) DrawTopology(Surface, DrawRect, _Proj, true);
    }
#if 0
    StartupStore(_T("... Experimental1=%.0f\n"), Experimental1);
    StartupStore(_T("... Experimental2=%.0f\n"), Experimental2);
    Experimental1 = 0.0;
    Experimental2 = 0.0;
#endif

    // Topology labels are printed first, using OLD wps positions from previous run!
    // Reset for topology labels decluttering engine occurs also in another place here!
    ResetLabelDeclutter();

    if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) {
        DrawTaskAAT(Surface, DrawRect);
    }


    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    if (IsMultimapAirspace()) {
        DrawAirSpace(Surface, rc, _Proj);
    }

    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    // In QUICKDRAW dont draw trail, thermals, glide terrain
    if (QUICKDRAW) {
        goto _skip_stuff;
    }

    DrawThermalEstimate(Surface, DrawRect, _Proj);
    if (OvertargetMode == OVT_THER) DrawThermalEstimateMultitarget(Surface, DrawRect, _Proj);

    // draw red cross on glide through terrain marker
    if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) {
        DrawGlideThroughTerrain(Surface, DrawRect, _Proj);
    }

    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

_skip_stuff:

    if (IsMultimapAirspace() && AirspaceWarningMapLabels) {
        DrawAirspaceLabels(Surface, DrawRect, _Proj, Orig_Aircraft);
        if (DONTDRAWTHEMAP) { // 100319
            goto QuickRedraw;
        }
    }

    if (IsMultimapWaypoints()) {
        DrawWaypointsNew(Surface, DrawRect);
    }
    if (TrailActive) {
        LKDrawLongTrail(Surface, Orig_Aircraft, DrawRect);
        // NEED REWRITING
        LKDrawTrail(Surface, DrawRect, _Proj);
    }
    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) {
        DrawTask(Surface, DrawRect, _Proj, Orig_Aircraft);

    }
    if (Flags_DrawFAI) {
        if (MapWindow::DerivedDrawInfo.Flying) { // FAI optimizer does not depend on tasks, being based on trace
            DrawFAIOptimizer(Surface, DrawRect, _Proj, Orig_Aircraft);
        } else { // not flying => show FAI sectors for the task
            if (ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) {
                DrawTaskSectors(Surface, DrawRect, _Proj);
            }
        }
    }


    // In QUICKDRAW do not paint other useless stuff
    if (QUICKDRAW) {
        if (extGPSCONNECT) DrawBearing(Surface, DrawRect, _Proj);
        goto _skip_2;
    }

    // ---------------------------------------------------

    DrawTeammate(Surface, rc, _Proj);

    if (extGPSCONNECT) {
        DrawBestCruiseTrack(Surface, Orig_Aircraft);
        DrawBearing(Surface, DrawRect, _Proj);
    }

    // draw wind vector at aircraft
    if (NOTANYPAN) {
        DrawWindAtAircraft2(Surface, Orig_Aircraft, DrawRect);
    } else if (mode.Is(Mode::MODE_TARGET_PAN)) {
        DrawWindAtAircraft2(Surface, Orig, rc);
    }

    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    // Draw traffic and other specifix LK gauges
    LKDrawFLARMTraffic(Surface, DrawRect, _Proj, Orig_Aircraft);

    // ---------------------------------------------------
_skip_2:

    if (NOTANYPAN) {

        if (IsMultimapOverlaysGauges()) {
            RenderOverlayGauges(Surface, rc);
        }
        
        if (TrackBar) {
            DrawHeading(Surface, Orig, DrawRect);
            if (ISGAAIRCRAFT) {
                DrawFuturePos(Surface, Orig, DrawRect);
            }
        }
        
        if (ISGAAIRCRAFT) {
            DrawHSIarc(Surface, Orig, DrawRect);
        }        

        if (IsMultimapOverlaysText()) {
            DrawLook8000(Surface, rc);
        }
        DrawBottomBar(Surface, rc);
    }

    if (DONTDRAWTHEMAP) {
        goto QuickRedraw;
    }

    // Draw glider or paraglider
    if (extGPSCONNECT) {
        DrawAircraft(Surface, Orig_Aircraft);
    }



#if USETOPOMARKS
    // marks on top...
    DrawMarks(hdc, rc);
#endif

    if (!INPAN) {
        DrawMapScale(Surface, rc, zoom.BigZoom()); // unused BigZoom
        DrawCompass(Surface, rc, DisplayAngle);
    }

#ifdef DRAWDEBUG
    DrawDebug(hdc, rc);
#endif

}
Exemple #6
0
void
MapWindow::Render(Canvas &canvas, const PixelRect &rc)
{ 
  render_projection = visible_projection;

  // Calculate screen position of the aircraft
  const RasterPoint aircraft_pos =
      render_projection.GeoToScreen(Basic().Location);

  // reset label over-write preventer
  label_block.reset();

  // Render terrain, groundline and topography
  RenderTerrain(canvas);
  RenderTopography(canvas);
  RenderFinalGlideShading(canvas);

  // Render track bearing (ground track)
  DrawTrackBearing(canvas, aircraft_pos);

  // Render airspace
  RenderAirspace(canvas);

  // Render task, waypoints
  DrawTask(canvas);
  DrawWaypoints(canvas);

  // Render weather/terrain max/min values
  if (!m_background.DrawSpotHeights(canvas, label_block))
    DrawTaskOffTrackIndicator(canvas);

  // Render the snail trail
  RenderTrail(canvas, aircraft_pos);

  RenderMarks(canvas);

  // Render estimate of thermal location
  DrawThermalEstimate(canvas);

  // Render topography on top of airspace, to keep the text readable
  RenderTopographyLabels(canvas);

  // Render glide through terrain range
  RenderGlide(canvas);

  DrawBestCruiseTrack(canvas, aircraft_pos);

  DrawAirspaceIntersections(canvas);

  // Draw wind vector at aircraft
  DrawWind(canvas, aircraft_pos, rc);

  // Draw traffic
  DrawTeammate(canvas);
  DrawFLARMTraffic(canvas, aircraft_pos);

  // Finally, draw you!
  if (Basic().Connected)
    Graphics::DrawAircraft(canvas, settings_map,
                           Calculated().Heading - render_projection.GetScreenAngle(),
                           aircraft_pos);

  // Render compass
  DrawCompass(canvas, rc);
}
Exemple #7
0
DWORD MapWindow::DrawThread (LPVOID lpvoid)
{

  FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime ;


  while ((!ProgramStarted) || (!Initialised)) {
	Sleep(100);
  }

  #if TRACETHREAD
  StartupStore(_T("##############  DRAW threadid=%d\n"),GetCurrentThreadId());
  #endif


  // THREADRUNNING = FALSE;
  THREADEXIT = FALSE;

  // Reset common topology and waypoint label declutter, first init. Done also in other places.
  ResetLabelDeclutter();

  GetClientRect(hWndMapWindow, &MapRect);
  // Default draw area is full screen, no opacity
  DrawRect=MapRect;

  UpdateTimeStats(true);

  
  SetBkMode(hdcDrawWindow,TRANSPARENT);
  SetBkMode(hDCTemp,OPAQUE);
  SetBkMode(hDCMask,OPAQUE);

  // paint draw window black to start
  SelectObject(hdcDrawWindow, GetStockObject(BLACK_PEN));
  Rectangle(hdcDrawWindow,MapRect.left,MapRect.top,
            MapRect.right,MapRect.bottom);

  BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left,
         MapRect.bottom-MapRect.top, 
         hdcDrawWindow, 0, 0, SRCCOPY);

  // This is just here to give fully rendered start screen
  UpdateInfo(&GPS_INFO, &CALCULATED_INFO);
  MapDirty = true;
  UpdateTimeStats(true);

  zoom.RequestedScale(zoom.Scale());
  zoom.ModifyMapScale();
  FillScaleListForEngineeringUnits();
  
  bool lastdrawwasbitblitted=false;
  bool first_run=true;

  // 
  // Big LOOP
  //

  while (!CLOSETHREAD) 
  {
	WaitForSingleObject(drawTriggerEvent, 5000);
	ResetEvent(drawTriggerEvent);
	if (CLOSETHREAD) break; // drop out without drawing

	if ((!THREADRUNNING) || (!GlobalRunning)) {
		Sleep(100);
		continue;
	}

	// This is also occuring on resolution change
	if (LKSW_ReloadProfileBitmaps) {
		#if TESTBENCH
		StartupStore(_T(".... SWITCH: ReloadProfileBitmaps detected\n"));
		#endif
		// This is needed to update resolution change
		GetClientRect(hWndMapWindow, &MapRect);
		DrawRect=MapRect;
		FillScaleListForEngineeringUnits();
		LKUnloadProfileBitmaps();
		LKLoadProfileBitmaps();
		LKUnloadFixedBitmaps();
		LKLoadFixedBitmaps();
		MapWindow::zoom.Reset();

		// This will reset the function for the new ScreenScale
		PolygonRotateShift((POINT*)NULL,0,0,0,DisplayAngle+1);

		// Restart from moving map
		if (MapSpaceMode!=MSM_WELCOME) SetModeType(LKMODE_MAP, MP_MOVING);

		LKSW_ReloadProfileBitmaps=false;
		// These should be better checked. first_run is forcing also cache update for topo.
		ForceRenderMap=true;
		first_run=true;
	}



	GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&StartKernelTime,&StartUserTime);

	// Until MapDirty is set true again, we shall only repaint the screen. No Render, no calculations, no updates.
	// This is intended for very fast immediate screen refresh.
	//
	// MapDirty is set true by:
	//   - TriggerRedraws()  in calculations thread
	//   - RefreshMap()      in drawthread generally
	//


	extern int XstartScreen, YstartScreen, XtargetScreen, YtargetScreen;
	extern bool OnFastPanning;
	// While we are moving in bitblt mode, ignore RefreshMap requests from LK
	// unless a timeout was triggered by MapWndProc itself.
	if (OnFastPanning) {
		MapDirty=false;
	} 

	// We must check if we are on FastPanning, because we may be in pan mode even while
	// the menu buttons are active and we are using them, accessing other functions.
	// In that case, without checking OnFastPanning, we would fall back here and repaint
	// with bitblt everytime, while instead we were asked a simple fastrefresh!
	//
	// Notice: we could be !MapDirty without OnFastPanning, of course!
	//
	if (!MapDirty && !ForceRenderMap && OnFastPanning && !first_run) {
		
		if (!mode.Is(Mode::MODE_TARGET_PAN) && mode.Is(Mode::MODE_PAN)) {

			int fromX=0, fromY=0;

			fromX=XstartScreen-XtargetScreen;
			fromY=YstartScreen-YtargetScreen;

			BitBlt(hdcScreen, 0, 0, 
				MapRect.right-MapRect.left, 
				MapRect.bottom-MapRect.top, 
				hdcDrawWindow, 0, 0, WHITENESS);


			BitBlt(hdcScreen, 0, 0,
				MapRect.right-MapRect.left,
				MapRect.bottom-MapRect.top, 
				hdcDrawWindow, 
				fromX,fromY, 				// source
				SRCCOPY);

			POINT centerscreen;
			centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2;
			DrawMapScale(hdcScreen,MapRect,false);
			DrawCrossHairs(hdcScreen, centerscreen, MapRect);
			lastdrawwasbitblitted=true;
		} else {
			// THIS IS NOT GOING TO HAPPEN!
			//
			// The map was not dirty, and we are not in fastpanning mode.
			// FastRefresh!  We simply redraw old bitmap. 
			//
			BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left,
				MapRect.bottom-MapRect.top, 
				hdcDrawWindow, 0, 0, SRCCOPY);

			lastdrawwasbitblitted=true;
		}

		// Now we can clear the flag. If it was off already, no problems.
		OnFastPanning=false;
		continue;

	} else {
		//
		// Else the map wasy dirty, and we must render it..
		// Notice: if we were fastpanning, than the map could not be dirty.
		//

		#if 1 // --------------------- EXPERIMENTAL, CHECK ZOOM IS WORKING IN PNA
		static double lasthere=0;
		// Only for special case: PAN mode, map not dirty (including requests for zooms!)
		// not in the ForceRenderMap run and last time was a real rendering. THEN, at these conditions,
		// we simply redraw old bitmap, for the scope of accelerating touch response.
		// In fact, if we are panning the map while rendering, there would be an annoying delay.
		// This is using lastdrawwasbitblitted
		if (INPAN && !MapDirty && !lastdrawwasbitblitted && !ForceRenderMap && !first_run) {
			// In any case, after 5 seconds redraw all
			if ( (LKHearthBeats-8) >lasthere ) {
				lasthere=LKHearthBeats;
				goto _dontbitblt;
			}
			BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left,
				MapRect.bottom-MapRect.top, 
				hdcDrawWindow, 0, 0, SRCCOPY);

			POINT centerscreen;
			centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2;
			DrawMapScale(hdcScreen,MapRect,false);
			DrawCrossHairs(hdcScreen, centerscreen, MapRect);
			continue;
		} 
		#endif // --------------------------
_dontbitblt:
		MapDirty = false;
		PanRefreshed=true;
	} // MapDirty

	lastdrawwasbitblitted=false;
	MapWindow::UpdateInfo(&GPS_INFO, &CALCULATED_INFO);

	RenderMapWindow(MapRect);
    
	if (!ForceRenderMap && !first_run) {
		BitBlt(hdcScreen, 0, 0, 
			MapRect.right-MapRect.left,
			MapRect.bottom-MapRect.top, 
			hdcDrawWindow, 0, 0, SRCCOPY);
		InvalidateRect(hWndMapWindow, &MapRect, false);
	}

	// Draw cross sight for pan mode, in the screen center, 
	// after a full repaint while not fastpanning
	if (mode.AnyPan() && !mode.Is(Mode::MODE_TARGET_PAN) && !OnFastPanning) {
		POINT centerscreen;
		centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2;
		DrawMapScale(hdcScreen,MapRect,false);
		DrawCompass(hdcScreen, MapRect, DisplayAngle);
		DrawCrossHairs(hdcScreen, centerscreen, MapRect);
	}

	UpdateTimeStats(false);

	// we do caching after screen update, to minimise perceived delay
	// UpdateCaches is updating topology bounds when either forced (only here)
	// or because MapWindow::ForceVisibilityScan  is set true.
	UpdateCaches(first_run);
	first_run=false;

	ForceRenderMap = false;

	if (ProgramStarted==psInitDone) {
		ProgramStarted = psFirstDrawDone;
	}

	if ( (GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&EndKernelTime,&EndUserTime)) == 0) {
		Cpu_Draw=9999;
	} else {
		Cpustats(&Cpu_Draw,&StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime);
	}
    
  } // Big LOOP

  #if TESTBENCH
  StartupStore(_T("... Thread_Draw terminated\n"));
  #endif
  THREADEXIT = TRUE;
  return 0;
}
Exemple #8
0
void
MapWindow::Render(Canvas &canvas, const PixelRect &rc)
{
  const NMEAInfo &basic = Basic();

  // reset label over-write preventer
  label_block.reset();

  render_projection = visible_projection;

  if (!render_projection.IsValid()) {
    canvas.ClearWhite();
    return;
  }

  // Calculate screen position of the aircraft
  PixelPoint aircraft_pos{0,0};
  if (basic.location_available)
      aircraft_pos = render_projection.GeoToScreen(basic.location);

  // General layout principles:
  // - lower elevation drawn on bottom layers
  // - increasing elevation drawn above
  // - increasing importance drawn above
  // - attempt to not obscure text

  //////////////////////////////////////////////// items on ground

  // Render terrain, groundline and topography
  draw_sw.Mark("RenderTerrain");
  RenderTerrain(canvas);

  draw_sw.Mark("RenderRasp");
  RenderRasp(canvas);

  draw_sw.Mark("RenderTopography");
  RenderTopography(canvas);

  draw_sw.Mark("RenderOverlays");
  RenderOverlays(canvas);

  draw_sw.Mark("DrawNOAAStations");
  RenderNOAAStations(canvas);

  //////////////////////////////////////////////// glide range info

  draw_sw.Mark("RenderFinalGlideShading");
  RenderFinalGlideShading(canvas);

  //////////////////////////////////////////////// airspace

  // Render airspace
  draw_sw.Mark("RenderAirspace");
  RenderAirspace(canvas);

  //////////////////////////////////////////////// task

  // Render task, waypoints
  draw_sw.Mark("DrawContest");
  DrawContest(canvas);

  draw_sw.Mark("DrawTask");
  DrawTask(canvas);

  draw_sw.Mark("DrawWaypoints");
  DrawWaypoints(canvas);

  //////////////////////////////////////////////// aircraft level items
  // Render the snail trail
  if (basic.location_available)
    RenderTrail(canvas, aircraft_pos);

  DrawWaves(canvas);

  // Render estimate of thermal location
  DrawThermalEstimate(canvas);

  //////////////////////////////////////////////// text items
  // Render topography on top of airspace, to keep the text readable
  draw_sw.Mark("RenderTopographyLabels");
  RenderTopographyLabels(canvas);

  //////////////////////////////////////////////// navigation overlays
  // Render glide through terrain range
  draw_sw.Mark("RenderGlide");
  RenderGlide(canvas);

  draw_sw.Mark("RenderMisc1");
  // Render weather/terrain max/min values
  DrawTaskOffTrackIndicator(canvas);

  // Render track bearing (projected track ground/air relative)
  draw_sw.Mark("DrawTrackBearing");
  RenderTrackBearing(canvas, aircraft_pos);

  draw_sw.Mark("RenderMisc2");
  DrawBestCruiseTrack(canvas, aircraft_pos);

  // Draw wind vector at aircraft
  if (basic.location_available)
    DrawWind(canvas, aircraft_pos, rc);

  // Render compass
  DrawCompass(canvas, rc);

  //////////////////////////////////////////////// traffic
  // Draw traffic

#ifdef HAVE_SKYLINES_TRACKING
  DrawSkyLinesTraffic(canvas);
#endif

  DrawTeammate(canvas);

  if (basic.location_available)
    DrawFLARMTraffic(canvas, aircraft_pos);

  //////////////////////////////////////////////// own aircraft
  // Finally, draw you!
  if (basic.location_available)
    AircraftRenderer::Draw(canvas, GetMapSettings(), look.aircraft,
                           basic.attitude.heading - render_projection.GetScreenAngle(),
                           aircraft_pos);

  //////////////////////////////////////////////// important overlays
  // Draw intersections on top of aircraft
  airspace_renderer.DrawIntersections(canvas, render_projection);
}
Exemple #9
0
void MapWindow::RenderMapWindowBg(HDC hdc, const RECT rc,
				  const POINT &Orig,
				  const POINT &Orig_Aircraft)
{

  // Calculations are taking time and slow down painting of map, beware
  #define MULTICALC_MINROBIN	5	// minimum split
  #define MULTICALC_MAXROBIN	20	// max split
  static short multicalc_slot=0;// -1 (which becomes immediately 0) will force full loading on startup, but this is not good
				// because currently we are not waiting for ProgramStarted=3
				// and the first scan is made while still initializing other things

  // TODO assign numslots with a function, based also on available CPU time
  short numslots=1;
  #if NEWSMARTZOOM
  static double quickdrawscale=0.0;
  static double delta_drawscale=1.0;
  #endif

  #if 0 
  extern void TestChangeRect();
  TestChangeRect();
  #endif

  if ((MapWindow::AlphaBlendSupported() && BarOpacity<100) || mode.AnyPan()) {
	MapWindow::ChangeDrawRect(MapRect);
  } else {
	RECT newRect={0,0,ScreenSizeX,ScreenSizeY-BottomSize};
	MapWindow::ChangeDrawRect(newRect);
  }

  if (QUICKDRAW) {
	goto _skip_calcs;
  }

  if (NumberOfWayPoints>200) {
	numslots=NumberOfWayPoints/400;
	// keep numslots optimal
	if (numslots<MULTICALC_MINROBIN) numslots=MULTICALC_MINROBIN; // seconds for full scan, as this is executed at 1Hz
	if (numslots>MULTICALC_MAXROBIN) numslots=MULTICALC_MAXROBIN;

	// When waypointnumber has changed, we wont be using an exceeded multicalc_slot, which would crash the sw
	// In this case, we shall probably continue for the first round to calculate without going from the beginning
	// but this is not a problem, we are round-robin all the time here.
	if (++multicalc_slot>numslots) multicalc_slot=1;
  } else {
	multicalc_slot=0; // forcing full scan
  }

  // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed
  // updating of visible landables, for example. The nearest pages do this separately, with their own sorting.
  // Basically we assume -like for nearest- that values will not change that much in the multicalc split time.
  // Target and tasks are recalculated in real time in any case. Nearest too. 
  LKCalculateWaypointReachable(multicalc_slot, numslots);

_skip_calcs:
  CalculateScreenPositionsAirspace(rc);

  CalculateScreenPositionsThermalSources();

  // Make the glide amoeba out of the latlon points, converting them to screen
  // (This function is updated for supporting multimaps )
  CalculateScreenPositionsGroundline();

  if (PGZoomTrigger) {
    if(!mode.Is(Mode::MODE_PANORAMA)) {
      mode.Special(Mode::MODE_SPECIAL_PANORAMA, true);
		LastZoomTrigger=DrawInfo.Time;
      
		Message::Lock();
	        Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s
		Message::Unlock();
		#ifndef DISABLEAUDIO
		if (EnableSoundModes) LKSound(TEXT("LK_TONEUP.WAV"));
		#endif
    }
    else {
		// previously called, see if time has passed
		if ( DrawInfo.Time > (LastZoomTrigger + 20.0)) {
			// time has passed, lets go back
			LastZoomTrigger=0; // just for safety
        mode.Special(Mode::MODE_SPECIAL_PANORAMA, false);
			PGZoomTrigger=false;
			Message::Lock(); 
	        	Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM
			Message::Unlock();
			#ifndef DISABLEAUDIO
			if (EnableSoundModes) LKSound(TEXT("LK_TONEDOWN.WAV"));
			#endif
		}
	}
  }

  // 
  // "Checkpoint Charlie"
  // This is were we process stuff for anything else but main map.
  // We let the calculations run also for MapSpace modes.
  // But for multimaps, we can also draw some more stuff..
  // We are also sent back here from next code, when we detect that
  // the MapSpace mode has changed from MAP to something else while we
  // were rendering.
  //
QuickRedraw:
  //
  if (DONTDRAWTHEMAP) 
  {
	DrawMapSpace(hdc, rc);
	// Is this a "shared map" environment? 
	if (IsMultiMapShared()) { 
		// Shared map, of course not MSN_MAP, since dontdrawthemap was checked
		//
		if (IsMultimapOverlaysText()) {
			DrawLook8000(hdc,rc);
		}
		if (IsMultimapOverlaysGauges()) {
			if (LKVarioBar) LKDrawVario(hdc,rc);

			if ((mode.Is(Mode::MODE_CIRCLING)) )
				if (ThermalBar) DrawThermalBand(hdcDrawWindow, rc);

			DrawFinalGlide(hdcDrawWindow,rc);
		}

	} else {
		// Not in map painting environment 
		// ex. nearest pages, but also MAPRADAR..
	}

	// 
	DrawBottomBar(hdc,rc);
#ifdef CPUSTATS
	DrawCpuStats(hdc,rc);
#endif
#ifdef DRAWDEBUG
	DrawDebug(hdc,rc);
#endif
	// no need to do SelectObject as at the bottom of function
	return;
  }

  // When no terrain is painted, set a background0
  // Remember that in this case we have plenty of cpu time to spend for best result
  if (!IsMultimapTerrain() || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded() ) {

    // display border and fill background..
	SelectObject(hdc, hInvBackgroundBrush[BgMapColor]);
	SelectObject(hdc, GetStockObject(WHITE_PEN));

	Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom);
	// We force LK painting black values on screen depending on the background color in use
	// TODO make it an array once settled
	// blackscreen would force everything to be painted white, instead
	LKTextBlack=BgMapColorTextBlack[BgMapColor];
	if (BgMapColor>6 ) BlackScreen=true; else BlackScreen=false; 
  } else {
	LKTextBlack=false;
	BlackScreen=false;
  }

  #if NEWSMARTZOOM
  // Copy the old background map with no overlays
  if (ONSMARTZOOM) {

	if (quickdrawscale>0) {
		delta_drawscale=zoom.DrawScale() / quickdrawscale;
	}

// StartupStore(_T("... QuickDrawScale=%.2f new zoom=%.2f  delta=%.2f\n"),quickdrawscale,zoom.DrawScale(),delta_drawscale);

	int dx=MapRect.right-MapRect.left;
	int dy=MapRect.bottom-MapRect.top;

	// notice: zoom in is always ok.. but zoom out starting from high zoom levels will make the picture
	// very small and unusable. We can consider to zoom out in fast zoom normally, in such cases?
	//
	// Notice 2: the delta is not yet working correctly 
	//
	if (delta_drawscale>1.0) {
		// zoom in
		StretchBlt(hdcDrawWindow, 
			0,0,
			dx,dy, 
			hdcQuickDrawWindow,
			(int)((dx/2) - (dx / delta_drawscale)/2),
			(int)((dy/2) - (dy / delta_drawscale)/2),
			(int)(dx / delta_drawscale),
			(int)(dy / delta_drawscale), 
			SRCCOPY);
	} else {
		// zoom out
		StretchBlt(hdcDrawWindow,
			(int)((dx/2) - (dx * delta_drawscale)/2),
			(int)((dy/2) - (dy * delta_drawscale)/2),
			(int)(dx * delta_drawscale),
			(int)(dy * delta_drawscale), 
			hdcQuickDrawWindow,
			0,0,
			dx,dy,  
			SRCCOPY);
	}
  }
  #endif


  // Logic of DONTDRAWTHEMAP is the following:
  // We are rendering the screen page here. If we are here, we passed Checkpoint Charlie.
  // So we were, at charlie, in MSM_MAP: preparing the main map stuff.
  // If we detect that MapSpace has CHANGED while we were doing our job here,
  // it means that the user has clicked meanwhile. He desires another page, so let's
  // reset our intentions and go back to beginning, or nearby..
  // We have a new job to do, for another MapSpace, no more MAP.
  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  #if NEWSMARTZOOM
  if ( OFFSMARTZOOM ) {
  #endif

  bool terrainpainted=false;

  if ((IsMultimapTerrain() && (DerivedDrawInfo.TerrainValid) 
       && RasterTerrain::isTerrainLoaded())
	) {
	// sunelevation is never used, it is still a todo in Terrain
	double sunelevation = 40.0;
	double sunazimuth=GetAzimuth();

    LockTerrainDataGraphics();
 	if (DONTDRAWTHEMAP) { // 100318
		UnlockTerrainDataGraphics();
		goto QuickRedraw;
	}
    DrawTerrain(hdc, DrawRect, sunazimuth, sunelevation);
    terrainpainted=true;
 	if (DONTDRAWTHEMAP) {
		UnlockTerrainDataGraphics();
		goto QuickRedraw;
	}
    if (!QUICKDRAW) {
    	// SHADED terrain unreachable, aka glide amoeba. This is not the outlined perimeter!
        #ifdef GTL2
    	if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && 
            DerivedDrawInfo.TerrainValid) {
        #else
    	if ((FinalGlideTerrain==2) && DerivedDrawInfo.TerrainValid) {
        #endif
    	  DrawTerrainAbove(hdc, DrawRect);
    	}
    }
    UnlockTerrainDataGraphics();
  }

  #if NEWSMARTZOOM
  }
  #endif

  //
  // REMINDER: WE ARE IN MAIN MAP HERE: MSM_MAP ONLY, OR PANNING MODE!
  // MAPSPACEMODE CAN STILL CHANGE, DUE TO USER INPUT. BUT WE GOT HERE IN
  // EITHER PAN OR MSM_MAP.
  //

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  if (IsMultimapTopology()) {
    DrawTopology(hdc, DrawRect);
  } else {
	// If no topology wanted, but terrain painted, we paint only water stuff
	if (terrainpainted) DrawTopology(hdc, DrawRect,true);
  }
  #if 0
  StartupStore(_T("... Experimental1=%.0f\n"),Experimental1);
  StartupStore(_T("... Experimental2=%.0f\n"),Experimental2);
  Experimental1=0.0;
  Experimental2=0.0;
  #endif

  // Topology labels are printed first, using OLD wps positions from previous run!
  // Reset for topology labels decluttering engine occurs also in another place here!
  ResetLabelDeclutter();
  
  if (Flags_DrawTask && ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) {
	DrawTaskAAT(hdc, DrawRect);
  }

  
  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  if (IsMultimapAirspace())
  {
    if ( (GetAirSpaceFillType() == asp_fill_ablend_full) || (GetAirSpaceFillType() == asp_fill_ablend_borders) )
      DrawTptAirSpace(hdc, rc);
    else
      DrawAirSpace(hdc, rc);	 // full screen, to hide clipping effect on low border
  }

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  // In QUICKDRAW dont draw trail, thermals, glide terrain
  if (QUICKDRAW) goto _skip_stuff;
 
  if(TrailActive) {
	// NEED REWRITING
	LKDrawTrail(hdc, Orig_Aircraft, DrawRect);
  }

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  DrawThermalEstimate(hdc, DrawRect);
  if (OvertargetMode==OVT_THER) DrawThermalEstimateMultitarget(hdc, DrawRect);
 
  // draw red cross on glide through terrain marker
  if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) {
    DrawGlideThroughTerrain(hdc, DrawRect);
  }
  
  if (DONTDRAWTHEMAP) { 
	goto QuickRedraw;
  }

_skip_stuff:

  if (IsMultimapAirspace() && AirspaceWarningMapLabels)
  {
	DrawAirspaceLabels(hdc, DrawRect, Orig_Aircraft);
	if (DONTDRAWTHEMAP) { // 100319
		goto QuickRedraw;
	}
  }

  if (IsMultimapWaypoints()) {
	DrawWaypointsNew(hdc,DrawRect);
  }

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  if (Flags_DrawTask && ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) {
	DrawTask(hdc, DrawRect, Orig_Aircraft);
  }

  // FAI optimizer does not depend on tasks, being based on trace
  if (Flags_DrawFAI)  DrawFAIOptimizer(hdc, DrawRect, Orig_Aircraft);

  // In QUICKDRAW do not paint other useless stuff
  if (QUICKDRAW) {
	if (extGPSCONNECT) DrawBearing(hdc, DrawRect);
	goto _skip_2;
  }

  // ---------------------------------------------------

  DrawTeammate(hdc, rc);

  if (extGPSCONNECT) {
    DrawBestCruiseTrack(hdc, Orig_Aircraft);
    DrawBearing(hdc, DrawRect);
  }

  // draw wind vector at aircraft
  if (NOTANYPAN) {
    DrawWindAtAircraft2(hdc, Orig_Aircraft, DrawRect);
  } else if (mode.Is(Mode::MODE_TARGET_PAN)) {
    DrawWindAtAircraft2(hdc, Orig, rc);
  }

  #if NEWSMARTZOOM
  // Save the current rendered map before painting overlays
  if ( OFFSMARTZOOM ) {
	quickdrawscale=zoom.DrawScale();
	BitBlt(hdcQuickDrawWindow, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top,
		hdcDrawWindow, 0, 0, SRCCOPY);
  }
  #endif

  // VisualGlide drawn BEFORE lk8000 overlays
  if (NOTANYPAN && (VisualGlide > 0)) {
    DrawGlideCircle(hdc, Orig, rc); 
  }

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }

  // Draw traffic and other specifix LK gauges
  LKDrawFLARMTraffic(hdc, DrawRect, Orig_Aircraft);

  // ---------------------------------------------------
_skip_2:

  if (NOTANYPAN) {
    // REMINDER TODO let it be configurable for not circling also, as before
    if ((mode.Is(Mode::MODE_CIRCLING)) )
      if (ThermalBar) DrawThermalBand(hdcDrawWindow, rc); // 091122
  
    if (IsMultimapOverlaysText()) DrawLook8000(hdc,rc); 
    DrawBottomBar(hdc,rc);
  }

  if (DONTDRAWTHEMAP) {
	goto QuickRedraw;
  }
    
  if (IsMultimapOverlaysGauges() && (LKVarioBar && NOTANYPAN)) 
	LKDrawVario(hdc,rc);
  
  // Draw glider or paraglider
  if (extGPSCONNECT) {
    DrawAircraft(hdc, Orig_Aircraft);
  }

  if (NOTANYPAN && !QUICKDRAW) {
	if (TrackBar) DrawHeading(hdc, Orig, DrawRect); 
  }

  #if USETOPOMARKS
  // marks on top...
  DrawMarks(hdc, rc);
  #endif

  if (ISGAAIRCRAFT && IsMultimapOverlaysGauges() && NOTANYPAN) DrawHSI(hdc,Orig,DrawRect); 

  if (!INPAN) {
	DrawMapScale(hdcDrawWindow,rc, zoom.BigZoom()); // unused BigZoom
	DrawCompass(hdcDrawWindow, rc, DisplayAngle);
  }

  if (IsMultimapOverlaysGauges() && NOTANYPAN) DrawFinalGlide(hdcDrawWindow,rc);


#ifdef CPUSTATS
  DrawCpuStats(hdc,rc);
#endif
#ifdef DRAWDEBUG
  DrawDebug(hdc,rc);
#endif

}