Esempio n. 1
0
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(), &nothingToRasterize, 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));
    }
}