// TODO code: optimise airspace drawing (same as DrawAirSpace()) // draw airspace using alpha blending //static void MapWindow::DrawTptAirSpace(HDC hdc, const RECT rc) { // since standard GDI functions (brushes, pens...) ignore alpha octet in ARGB // color value and don't set it in the resulting bitmap, we cannot use // perpixel alpha blending, instead we use global opacity for alpha blend // (same opacity for all pixels); for fully "transparent" areas (without // airspace) we must copy destination bitmap into source bitmap first so that // alpha blending of such areas results in the same pixels as origin pixels // in destination CAirspaceList::const_iterator it; CAirspaceList::const_reverse_iterator itr; const CAirspaceList& airspaces_to_draw = CAirspaceManager::Instance().GetNearAirspacesRef(); int airspace_type; bool found = false; bool borders_only = (GetAirSpaceFillType() == asp_fill_ablend_borders); HDC hdcbuffer = NULL; HBITMAP hbbufferold = NULL, hbbuffer = NULL; static bool asp_selected_flash = false; asp_selected_flash = !asp_selected_flash; if (borders_only) { // Prepare layers hdcbuffer = CreateCompatibleDC(hdc); hbbuffer = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top); hbbufferold = (HBITMAP)SelectObject(hdcbuffer, hbbuffer); BitBlt(hdcbuffer, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, rc.left, rc.top, BLACKNESS ); SelectObject(hdcbuffer, GetStockObject(NULL_PEN)); BitBlt(hDCMask, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, rc.left, rc.top, BLACKNESS ); SelectObject(hDCMask, hAirspaceBorderPen); SelectObject(hDCMask, GetStockObject(HOLLOW_BRUSH)); } // Draw airspace area if (1) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); if (borders_only) { // Draw in reverse order! // The idea behind this, is lower top level airspaces are smaller. (statistically) // They have to be draw later, because inside border area have to be in correct color, // not the color of the bigger airspace above this small one. for (itr=airspaces_to_draw.rbegin(); itr != airspaces_to_draw.rend(); ++itr) { if ((*itr)->DrawStyle() == adsFilled) { airspace_type = (*itr)->Type(); if (!found) { found = true; ClearTptAirSpace(hdc, rc); } // set filling brush SelectObject(hdcbuffer, GetAirSpaceSldBrushByClass(airspace_type)); (*itr)->Draw(hdcbuffer, rc, true); (*itr)->Draw(hDCMask, rc, false); } }//for } else { // Draw in direct order! for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) { if ((*it)->DrawStyle() == adsFilled) { airspace_type = (*it)->Type(); if (!found) { found = true; ClearTptAirSpace(hdc, rc); } // set filling brush SelectObject(hDCTemp, GetAirSpaceSldBrushByClass(airspace_type)); (*it)->Draw(hDCTemp, rc, true); } }//for }//else borders_only }//mutex release // alpha blending if (found) { if (borders_only) { #if (WINDOWSPC<1) TransparentImage(hdcbuffer, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, hDCMask, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, RGB_WHITE ); TransparentImage(hDCTemp, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, hdcbuffer, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, RGB_BLACK ); #else TransparentBlt(hdcbuffer, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, hDCMask, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, RGB_WHITE ); TransparentBlt(hDCTemp, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, hdcbuffer, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, RGB_BLACK ); #endif } DoAlphaBlend(hdc, rc, hDCTemp, rc, (255 * GetAirSpaceOpacity()) / 100); } // draw it again, just the outlines // we will be drawing directly into given hdc, so store original PEN object HPEN hOrigPen = (HPEN) SelectObject(hdc, GetStockObject(WHITE_PEN)); if (1) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) { if ((*it)->DrawStyle()) { airspace_type = (*it)->Type(); if (bAirspaceBlackOutline ^ (asp_selected_flash && (*it)->Selected()) ) { SelectObject(hdc, GetStockObject(BLACK_PEN)); } else { SelectObject(hdc, hAirspacePens[airspace_type]); } (*it)->Draw(hdc, rc, false); } }//for } if (borders_only) { // Free up GDI resources SelectObject(hdcbuffer, hbbufferold); DeleteObject(hbbuffer); DeleteDC(hdcbuffer); } // restore original PEN SelectObject(hdc, hOrigPen); } // DrawTptAirSpace()
// TODO code: optimise airspace drawing (same as DrawAirSpace()) // draw airspace using alpha blending //static void MapWindow::DrawTptAirSpace(HDC hdc, const RECT rc) { // since standard GDI functions (brushes, pens...) ignore alpha octet in ARGB // color value and don't set it in the resulting bitmap, we cannot use // perpixel alpha blending, instead we use global opacity for alpha blend // (same opacity for all pixels); for fully "transparent" areas (without // airspace) we must copy destination bitmap into source bitmap first so that // alpha blending of such areas results in the same pixels as origin pixels // in destination CAirspaceList::const_iterator it; CAirspaceList::const_reverse_iterator itr; const CAirspaceList& airspaces_to_draw = CAirspaceManager::Instance().GetNearAirspacesRef(); int airspace_type; bool found = false; bool borders_only = (GetAirSpaceFillType() == asp_fill_ablend_borders); bool outlined_only=(GetAirSpaceFillType()==asp_fill_border_only); static bool asp_selected_flash = false; asp_selected_flash = !asp_selected_flash; int nDC1 = SaveDC(mhdcbuffer); int nDC2 = SaveDC(hDCMask); int nDC3 = SaveDC(hDCTemp); // Draw airspace area if (1) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); if (borders_only) { // Draw in reverse order! // The idea behind this, is lower top level airspaces are smaller. (statistically) // They have to be draw later, because inside border area have to be in correct color, // not the color of the bigger airspace above this small one. for (itr=airspaces_to_draw.rbegin(); itr != airspaces_to_draw.rend(); ++itr) { if ((*itr)->DrawStyle() == adsFilled) { airspace_type = (*itr)->Type(); if (!found) { found = true; ClearTptAirSpace(hdc, rc); } // set filling brush SelectObject(mhdcbuffer, GetAirSpaceSldBrushByClass(airspace_type)); (*itr)->Draw(mhdcbuffer, rc, true); (*itr)->Draw(hDCMask, rc, false); } }//for } else { // Draw in direct order! for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) { if ((*it)->DrawStyle() == adsFilled) { airspace_type = (*it)->Type(); if (!found) { found = true; ClearTptAirSpace(hdc, rc); } // set filling brush SelectObject(hDCTemp, GetAirSpaceSldBrushByClass(airspace_type)); (*it)->Draw(hDCTemp, rc, true); } }//for }//else borders_only }//mutex release // alpha blending if (found) { if (borders_only) { MaskBlt(hDCTemp, rc.left,rc.top, rc.right-rc.left,rc.bottom-rc.top, mhdcbuffer,rc.left,rc.top, hMaskBitMap,rc.left,rc.top, MAKEROP4(SRCAND, 0x00AA0029)); } DoAlphaBlend(hdc, rc, hDCTemp, rc, (255 * GetAirSpaceOpacity()) / 100); } // draw it again, just the outlines // we will be drawing directly into given hdc, so store original PEN object HPEN hOrigPen = (HPEN) SelectObject(hdc, GetStockObject(WHITE_PEN)); if (1) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); for (it=airspaces_to_draw.begin(); it != airspaces_to_draw.end(); ++it) { if ((*it)->DrawStyle()) { airspace_type = (*it)->Type(); if ( (((*it)->DrawStyle()==adsFilled)&&!outlined_only&&!borders_only) ^ (asp_selected_flash && (*it)->Selected()) ) { SelectObject(hdc, GetStockObject(BLACK_PEN)); } else { SelectObject(hdc, hAirspacePens[airspace_type]); } (*it)->Draw(hdc, rc, false); } }//for } // restore original PEN SelectObject(hdc, hOrigPen); RestoreDC(mhdcbuffer, nDC1); RestoreDC(hDCMask, nDC2); RestoreDC(hDCTemp, nDC3); } // DrawTptAirSpace()