static void * pixelsInit(GLenum format, GLenum type) { switch(format) { case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_LUMINANCE: case GL_DEPTH_COMPONENT: case GL_STENCIL_INDEX: return (allocPixels(format, type, 1)); case GL_LUMINANCE_ALPHA: case GL_RG: return (allocPixels(format, type, 2)); case GL_RGB: case GL_BGR: return (allocPixels(format, type, 3)); case GL_RGBA: case GL_BGRA: return (allocPixels(format, type, 4)); default: printf("format = %s not allowed in glDrawPixels()\n", piglit_get_gl_enum_name(format)); piglit_report_result(PIGLIT_FAIL); } return NULL; }
bool OsmAnd::OfflineMapRasterTileProvider_GPU_P::obtainTile(const TileId& tileId, const ZoomLevel& zoom, std::shared_ptr<MapTile>& outTile) { // Get bounding box that covers this tile const auto tileBBox31 = Utilities::tileBoundingBox31(tileId, zoom); // Obtain OBF data interface const auto& dataInterface = owner->dataProvider->obfsCollection->obtainDataInterface(); // Get map objects from data proxy QList< std::shared_ptr<const Model::MapObject> > mapObjects; #if defined(_DEBUG) || defined(DEBUG) const auto dataRead_Begin = std::chrono::high_resolution_clock::now(); #endif bool basemapAvailable; MapFoundationType tileFoundation; dataInterface->obtainBasemapPresenceFlag(basemapAvailable, nullptr); dataInterface->obtainMapObjects(&mapObjects, &tileFoundation, tileBBox31, zoom, nullptr); #if defined(_DEBUG) || defined(DEBUG) const auto dataRead_End = std::chrono::high_resolution_clock::now(); const std::chrono::duration<float> dataRead_Elapsed = dataRead_End - dataRead_Begin; #endif #if defined(_DEBUG) || defined(DEBUG) const auto dataRasterization_Begin = std::chrono::high_resolution_clock::now(); #endif //TODO: SkGpuDevice // Allocate rasterization target auto rasterizationSurface = new SkBitmap(); rasterizationSurface->setConfig(SkBitmap::kARGB_8888_Config, outputTileSize, outputTileSize); if(!rasterizationSurface->allocPixels()) { delete rasterizationSurface; LogPrintf(LogSeverityLevel::Error, "Failed to allocate buffer for ARGB8888 rasterization surface %dx%d", outputTileSize, outputTileSize); return false; } SkBitmapDevice rasterizationTarget(*rasterizationSurface); // Create rasterization canvas SkCanvas canvas(&rasterizationTarget); // Perform actual rendering bool nothingToRasterize = false; RasterizerEnvironment rasterizerEnv(owner->dataProvider->mapStyle, basemapAvailable, density); RasterizerContext rasterizerContext; Rasterizer::prepareContext(rasterizerEnv, rasterizerContext, tileBBox31, zoom, outputTileSize, tileFoundation, mapObjects, OsmAnd::PointF(), ¬hingToRasterize, nullptr); if(!nothingToRasterize) Rasterizer::rasterizeMap(rasterizerEnv, rasterizerContext, true, canvas, nullptr); #if defined(_DEBUG) || defined(DEBUG) const auto dataRasterization_End = std::chrono::high_resolution_clock::now(); const std::chrono::duration<float> dataRasterization_Elapsed = dataRasterization_End - dataRasterization_Begin; if(!nothingToRasterize) { LogPrintf(LogSeverityLevel::Info, "%d map objects from %dx%d@%d: reading %fs, rasterization %fs", mapObjects.count(), tileId.x, tileId.y, zoom, dataRead_Elapsed.count(), dataRasterization_Elapsed.count()); } else { LogPrintf(LogSeverityLevel::Info, "%d map objects from %dx%d@%d: reading %fs, nothing to rasterize (%fs)", mapObjects.count(), tileId.x, tileId.y, zoom, dataRead_Elapsed.count(), dataRasterization_Elapsed.count()); } #endif // If there is no data to rasterize, tell that this tile is not available if(nothingToRasterize) { delete rasterizationSurface; outTile.reset(); return true; } // Or supply newly rasterized tile auto tile = new MapBitmapTile(rasterizationSurface, MapBitmapTile::AlphaChannelData::NotPresent); outTile.reset(tile); return true; }
bool OsmAnd::OfflineMapRasterTileProvider_Software_P::obtainTile(const TileId tileId, const ZoomLevel zoom, std::shared_ptr<const MapTile>& outTile, const IQueryController* const queryController) { // Obtain offline map data tile std::shared_ptr< const OfflineMapDataTile > dataTile; owner->dataProvider->obtainTile(tileId, zoom, dataTile); if (!dataTile) { outTile.reset(); return true; } #if OSMAND_PERFORMANCE_METRICS const auto dataRasterization_Begin = std::chrono::high_resolution_clock::now(); #endif // OSMAND_PERFORMANCE_METRICS // Allocate rasterization target auto rasterizationSurface = new SkBitmap(); rasterizationSurface->setConfig(SkBitmap::kARGB_8888_Config, outputTileSize, outputTileSize); if (!rasterizationSurface->allocPixels()) { delete rasterizationSurface; LogPrintf(LogSeverityLevel::Error, "Failed to allocate buffer for ARGB8888 rasterization surface %dx%d", outputTileSize, outputTileSize); return false; } SkBitmapDevice rasterizationTarget(*rasterizationSurface); // Create rasterization canvas SkCanvas canvas(&rasterizationTarget); // Perform actual rendering if (!dataTile->nothingToRasterize) { Rasterizer rasterizer(dataTile->rasterizerContext); rasterizer.rasterizeMap(canvas, true, nullptr, queryController); } #if OSMAND_PERFORMANCE_METRICS const auto dataRasterization_End = std::chrono::high_resolution_clock::now(); const std::chrono::duration<float> dataRasterization_Elapsed = dataRasterization_End - dataRasterization_Begin; if (!dataTile->nothingToRasterize) { LogPrintf(LogSeverityLevel::Info, "%d map objects in %dx%d@%d: rasterization %fs", dataTile->mapObjects.count(), tileId.x, tileId.y, zoom, dataRasterization_Elapsed.count()); } else { LogPrintf(LogSeverityLevel::Info, "%d map objects in %dx%d@%d: nothing to rasterize (%fs)", dataTile->mapObjects.count(), tileId.x, tileId.y, zoom, dataRasterization_Elapsed.count()); } #endif // OSMAND_PERFORMANCE_METRICS // If there is no data to rasterize, tell that this tile is not available if (dataTile->nothingToRasterize) { delete rasterizationSurface; outTile.reset(); return true; } // Or supply newly rasterized tile auto tile = new Tile(rasterizationSurface, dataTile); outTile.reset(tile); return true; }
void OsmAnd::SymbolRasterizer_P::rasterize( const std::shared_ptr<const Primitiviser::PrimitivisedArea>& primitivizedArea, QList< std::shared_ptr<const RasterizedSymbolsGroup> >& outSymbolsGroups, std::function<bool (const std::shared_ptr<const Model::BinaryMapObject>& mapObject)> filter, const IQueryController* const controller) { const auto& env = primitivizedArea->mapPresentationEnvironment; for (const auto& symbolGroupEntry : rangeOf(constOf(primitivizedArea->symbolsGroups))) { if (controller && controller->isAborted()) return; const auto& mapObject = symbolGroupEntry.key(); const auto& symbolsGroup = symbolGroupEntry.value(); ////////////////////////////////////////////////////////////////////////// //if ((mapObject->id >> 1) == 189600735u) //{ // int i = 5; //} //else // continue; ////////////////////////////////////////////////////////////////////////// // Apply filter, if it's present if (filter && !filter(mapObject)) continue; // Create group const std::shared_ptr<RasterizedSymbolsGroup> group(new RasterizedSymbolsGroup(mapObject)); // Total offset allows several symbols to stack into column. Offset specifies center of symbol bitmap. // This offset is computed only in case symbol is not on-path and not along-path PointI totalOffset; for (const auto& symbol : constOf(symbolsGroup->symbols)) { if (controller && controller->isAborted()) return; if (const auto& textSymbol = std::dynamic_pointer_cast<const Primitiviser::TextSymbol>(symbol)) { TextRasterizer::Style style; if (!textSymbol->drawOnPath && textSymbol->shieldResourceName.isEmpty()) style.wrapWidth = textSymbol->wrapWidth; if (!textSymbol->shieldResourceName.isEmpty()) env->obtainTextShield(textSymbol->shieldResourceName, style.backgroundBitmap); style .setBold(textSymbol->isBold) .setColor(textSymbol->color) .setSize(textSymbol->size); if (textSymbol->shadowRadius > 0) { style .setHaloColor(textSymbol->shadowColor) .setHaloRadius(textSymbol->shadowRadius + 2 /*px*/); //NOTE: ^^^ This is same as specifying 'x:2' in style, but due to backward compatibility with Android, leave as-is } float lineSpacing; float symbolExtraTopSpace; float symbolExtraBottomSpace; QVector<SkScalar> glyphsWidth; const auto rasterizedText = TextRasterizer::globalInstance().rasterize( textSymbol->value, style, textSymbol->drawOnPath ? &glyphsWidth : nullptr, &symbolExtraTopSpace, &symbolExtraBottomSpace, &lineSpacing); if (!rasterizedText) continue; #if OSMAND_DUMP_SYMBOLS { QDir::current().mkpath("text_symbols"); std::unique_ptr<SkImageEncoder> encoder(CreatePNGImageEncoder()); QString filename; filename.sprintf("%s\\text_symbols\\%p.png", qPrintable(QDir::currentPath()), rasterizedText.get()); encoder->encodeFile(qPrintable(filename), *rasterizedText.get(), 100); } #endif // OSMAND_DUMP_SYMBOLS if (textSymbol->drawOnPath) { if (textSymbol->drawOnPath && textSymbol->verticalOffset > 0) { LogPrintf(LogSeverityLevel::Warning, "Hey, on-path + vertical offset is not supported!"); //assert(false); } // Publish new rasterized symbol const std::shared_ptr<RasterizedOnPathSymbol> rasterizedSymbol(new RasterizedOnPathSymbol(group, textSymbol)); rasterizedSymbol->bitmap = qMove(rasterizedText); rasterizedSymbol->order = textSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Text; rasterizedSymbol->content = textSymbol->value; rasterizedSymbol->languageId = textSymbol->languageId; rasterizedSymbol->minDistance = textSymbol->minDistance; rasterizedSymbol->glyphsWidth = glyphsWidth; group->symbols.push_back(qMove(rasterizedSymbol)); } else { // Calculate local offset. Since offset specifies center, it's a sum of // - vertical offset // - extra top space (which should be in texture, but not rendered, since transparent) // - height / 2 // This calculation is used only if this symbol is not first. Otherwise only following is used: // - vertical offset PointI localOffset; localOffset.y += textSymbol->verticalOffset; if (!group->symbols.isEmpty() && !textSymbol->drawAlongPath) { localOffset.y += symbolExtraTopSpace; localOffset.y += rasterizedText->height() / 2; } // Increment total offset if (!textSymbol->drawAlongPath) totalOffset += localOffset; // Publish new rasterized symbol const std::shared_ptr<RasterizedSpriteSymbol> rasterizedSymbol(new RasterizedSpriteSymbol(group, textSymbol)); rasterizedSymbol->bitmap = rasterizedText; rasterizedSymbol->order = textSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Text; rasterizedSymbol->content = textSymbol->value; rasterizedSymbol->languageId = textSymbol->languageId; rasterizedSymbol->minDistance = textSymbol->minDistance; rasterizedSymbol->location31 = textSymbol->location31; rasterizedSymbol->offset = textSymbol->drawAlongPath ? localOffset : totalOffset; rasterizedSymbol->drawAlongPath = textSymbol->drawAlongPath; rasterizedSymbol->intersectionSize = PointI(-1, -1); group->symbols.push_back(qMove(std::shared_ptr<const RasterizedSymbol>(rasterizedSymbol))); // Next symbol should also take into account: // - height / 2 // - extra bottom space (which should be in texture, but not rendered, since transparent) // - spacing between lines if (!textSymbol->drawAlongPath) { totalOffset.y += rasterizedText->height() / 2; totalOffset.y += symbolExtraBottomSpace; totalOffset.y += qCeil(lineSpacing); } } } else if (const auto& iconSymbol = std::dynamic_pointer_cast<const Primitiviser::IconSymbol>(symbol)) { std::shared_ptr<const SkBitmap> iconBitmap; if (!env->obtainMapIcon(iconSymbol->resourceName, iconBitmap) || !iconBitmap) continue; std::shared_ptr<const SkBitmap> backgroundBitmap; if (!iconSymbol->shieldResourceName.isEmpty()) env->obtainIconShield(iconSymbol->shieldResourceName, backgroundBitmap); // Compose final image std::shared_ptr<const SkBitmap> rasterizedIcon; if (!backgroundBitmap) rasterizedIcon = iconBitmap; else { // Compute composed image size const auto rasterizedIconWidth = qMax(iconBitmap->width(), backgroundBitmap->width()); const auto rasterizedIconHeight = qMax(iconBitmap->height(), backgroundBitmap->height()); // Create a bitmap that will be hold entire symbol const auto pRasterizedIcon = new SkBitmap(); rasterizedIcon.reset(pRasterizedIcon); pRasterizedIcon->setConfig(SkBitmap::kARGB_8888_Config, rasterizedIconWidth, rasterizedIconHeight); pRasterizedIcon->allocPixels(); pRasterizedIcon->eraseColor(SK_ColorTRANSPARENT); // Create canvas SkBitmapDevice target(*pRasterizedIcon); SkCanvas canvas(&target); // Draw the background canvas.drawBitmap(*backgroundBitmap, (rasterizedIconWidth - backgroundBitmap->width()) / 2.0f, (rasterizedIconHeight - backgroundBitmap->height()) / 2.0f, nullptr); // Draw the icon canvas.drawBitmap(*iconBitmap, (rasterizedIconWidth - iconBitmap->width()) / 2.0f, (rasterizedIconHeight - iconBitmap->height()) / 2.0f, nullptr); // Flush all operations canvas.flush(); } #if OSMAND_DUMP_SYMBOLS { QDir::current().mkpath("icon_symbols"); std::unique_ptr<SkImageEncoder> encoder(CreatePNGImageEncoder()); QString filename; filename.sprintf("%s\\icon_symbols\\%p.png", qPrintable(QDir::currentPath()), rasterizedIcon.get()); encoder->encodeFile(qPrintable(filename), *rasterizedIcon, 100); } #endif // OSMAND_DUMP_SYMBOLS // Calculate local offset. Since offset specifies center, it's a sum of // - height / 2 // This calculation is used only if this symbol is not first. Otherwise nothing is used. PointI localOffset; if (!group->symbols.isEmpty() && !iconSymbol->drawAlongPath) localOffset.y += rasterizedIcon->height() / 2; // Increment total offset if (!iconSymbol->drawAlongPath) totalOffset += localOffset; // Publish new rasterized symbol const std::shared_ptr<RasterizedSpriteSymbol> rasterizedSymbol(new RasterizedSpriteSymbol(group, iconSymbol)); rasterizedSymbol->bitmap = rasterizedIcon; rasterizedSymbol->order = iconSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Icon; rasterizedSymbol->content = iconSymbol->resourceName; rasterizedSymbol->languageId = LanguageId::Invariant; rasterizedSymbol->minDistance = PointI(); rasterizedSymbol->location31 = iconSymbol->location31; rasterizedSymbol->offset = iconSymbol->drawAlongPath ? localOffset : totalOffset; rasterizedSymbol->drawAlongPath = iconSymbol->drawAlongPath; rasterizedSymbol->intersectionSize = PointI(iconSymbol->intersectionSize, iconSymbol->intersectionSize); group->symbols.push_back(qMove(std::shared_ptr<const RasterizedSymbol>(rasterizedSymbol))); // Next symbol should also take into account: // - height / 2 if (!iconSymbol->drawAlongPath) totalOffset.y += rasterizedIcon->height() / 2; } } // Add group to output outSymbolsGroups.push_back(qMove(group)); } }