void GlueMapWindow::OnPaintBuffer(Canvas &canvas) { #ifdef ENABLE_OPENGL ExchangeBlackboard(); EnterDrawThread(); /* update terrain, topography, ... */ if (Idle()) /* still dirty: schedule a redraw to load more data */ data_timer.Schedule(500); else data_timer.Cancel(); #endif MapWindow::OnPaintBuffer(canvas); DrawMapScale(canvas, GetClientRect(), render_projection); if (IsPanning()) DrawPanInfo(canvas); #ifdef ENABLE_OPENGL LeaveDrawThread(); #endif }
void GlueMapWindow::OnPaintBuffer(Canvas &canvas) { #ifdef ENABLE_OPENGL ExchangeBlackboard(); EnterDrawThread(); /* update terrain, topography, ... */ Idle(); #endif MapWindow::OnPaintBuffer(canvas); DrawMapScale(canvas, GetClientRect(), render_projection); if (IsPanning()) DrawPanInfo(canvas); #ifdef ENABLE_OPENGL LeaveDrawThread(); #endif }
/** * 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); }
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::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 }
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; }
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 }