<commit_before>/*************************************************************************
 *
 *  $RCSfile: Pattern.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: fs $ $Date: 2002-12-02 09:56:35 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _FORMS_PATTERN_HXX_
#define _FORMS_PATTERN_HXX_

#ifndef _FORMS_EDITBASE_HXX_
#include "EditBase.hxx"
#endif

//.........................................................................
namespace frm
{
//.........................................................................

//==================================================================
//= OPatternModel
//==================================================================
class OPatternModel
                :public OEditBaseModel
                ,public ::comphelper::OAggregationArrayUsageHelper< OPatternModel >
{
    ::rtl::OUString         m_aSaveValue;

    static sal_Int32    nTextHandle;

protected:
    virtual void _onValueChanged();
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    DECLARE_DEFAULT_LEAF_XTOR( OPatternModel );

    // starform::XBoundComponent
    virtual sal_Bool _commit();

    // ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
    virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OPatternModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // ::com::sun::star::io::XPersistObject
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);

    // starform::XReset
    virtual void _reset();

    // OAggregationArrayUsageHelper
    virtual void fillProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps,
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rAggregateProps
        ) const;
    IMPLEMENT_INFO_SERVICE()

protected:
    DECLARE_XCLONEABLE();
};

//==================================================================
//= OPatternControl
//==================================================================
class OPatternControl: public OBoundControl
{
protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    OPatternControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OPatternControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();
};

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // _FORMS_PATTERN_HXX_

<commit_msg>INTEGRATION: CWS formcelllinkage (1.5.92); FILE MERGED 2003/10/01 09:18:32 fs 1.5.92.1: #i18994# merging the changes from the CWS fs002<commit_after>/*************************************************************************
 *
 *  $RCSfile: Pattern.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2003-10-21 08:59:57 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _FORMS_PATTERN_HXX_
#define _FORMS_PATTERN_HXX_

#ifndef _FORMS_EDITBASE_HXX_
#include "EditBase.hxx"
#endif

//.........................................................................
namespace frm
{
//.........................................................................

//==================================================================
//= OPatternModel
//==================================================================
class OPatternModel
                :public OEditBaseModel
                ,public ::comphelper::OAggregationArrayUsageHelper< OPatternModel >
{
private:
    ::rtl::OUString         m_aSaveValue;
protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    DECLARE_DEFAULT_LEAF_XTOR( OPatternModel );

    // ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
    virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OPatternModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // ::com::sun::star::io::XPersistObject
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun::star::uno::RuntimeException);

    // OAggregationArrayUsageHelper
    virtual void fillProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps,
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rAggregateProps
        ) const;
    IMPLEMENT_INFO_SERVICE()

protected:
    // OBoundControlModel overridables
    virtual ::com::sun::star::uno::Any
                            translateDbColumnToControlValue( );
    virtual sal_Bool        commitControlValueToDbColumn( bool _bPostReset );

    virtual ::com::sun::star::uno::Any
                            getDefaultForReset() const;

protected:
    DECLARE_XCLONEABLE();
};

//==================================================================
//= OPatternControl
//==================================================================
class OPatternControl: public OBoundControl
{
protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    OPatternControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OPatternControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();
};

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // _FORMS_PATTERN_HXX_

<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 mogemimi. Distributed under the MIT license.

#include "SpriteFont.hpp"
#include "TrueTypeFont.hpp"
#include "SpriteBatchRenderer.hpp"
#include "Pomdog/Math/Color.hpp"
#include "Pomdog/Math/Matrix4x4.hpp"
#include "Pomdog/Math/Vector2.hpp"
#include "Pomdog/Math/Vector3.hpp"
#include "Pomdog/Math/Radian.hpp"
#include "Pomdog/Graphics/Texture2D.hpp"
#include "Pomdog/Utility/Assert.hpp"

#ifndef _MSC_VER
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#endif
#include <utf8cpp/utf8.h>
#ifndef _MSC_VER
#pragma clang diagnostic pop
#endif

#include <unordered_map>

namespace Pomdog {
namespace {

static std::vector<std::uint8_t> ConvertTextureDataByteToByte4(std::uint8_t const* source, size_t size)
{
    std::vector<std::uint8_t> output;
    output.reserve(size * 4);

    for (size_t i = 0; i < size; ++i) {
        output.push_back(255);
        output.push_back(255);
        output.push_back(255);
        output.push_back(source[i]);
    }
    return std::move(output);
}

} // unnamed namespace
//-----------------------------------------------------------------------
// MARK: - SpriteFont::Impl
//-----------------------------------------------------------------------
class SpriteFont::Impl {
public:
    typedef Detail::SpriteFonts::Glyph Glyph;

    static constexpr int TextureWidth = 512;
    static constexpr int TextureHeight = 512;

    std::unordered_map<std::uint32_t, Glyph> spriteFontMap;

    std::uint32_t defaultCharacter;
    float lineSpacing;
    std::uint16_t spacing;

    Impl(std::vector<std::shared_ptr<Texture2D>> && textures,
        std::vector<Detail::SpriteFonts::Glyph> const& glyphs,
        std::uint32_t defaultCharacter,
        std::int16_t spacing,
        std::int16_t lineSpacing);

    Impl(std::shared_ptr<GraphicsDevice> const& graphicsDevice,
        std::shared_ptr<TrueTypeFont> const& font,
        std::uint32_t defaultCharacter,
        std::int16_t lineSpacing);

    Vector2 MeasureString(std::string const& text) const;

    void Draw(
        SpriteBatchRenderer & spriteBatch,
        std::string const& text,
        Vector2 const& position,
        Color const& color);

    void Draw(
        SpriteBatchRenderer & spriteBatch,
        std::string const& text,
        Vector2 const& position,
        Color const& color,
        Radian<float> const& rotation,
        //Vector2 const& originPivot,
        Vector2 const& scale);

    void PrepareFonts(std::string const& text);

private:
    std::vector<std::shared_ptr<Texture2D>> textures;
    std::shared_ptr<GraphicsDevice> graphicsDevice;
    std::shared_ptr<TrueTypeFont> font;
    std::vector<std::uint8_t> pixelData;
    Point2D currentPoint;
    int bottomY;
};
constexpr int SpriteFont::Impl::TextureWidth;
constexpr int SpriteFont::Impl::TextureHeight;
//-----------------------------------------------------------------------
SpriteFont::Impl::Impl(std::vector<std::shared_ptr<Texture2D>> && texturesIn,
    std::vector<Detail::SpriteFonts::Glyph> const& glyphsIn,
    std::uint32_t defaultCharacterIn, std::int16_t spacingIn, std::int16_t lineSpacingIn)
    : textures(std::move(texturesIn))
    , defaultCharacter(defaultCharacterIn)
    , spacing(spacingIn)
    , lineSpacing(lineSpacingIn)
{
    for (auto & glyph: glyphsIn) {
        spriteFontMap.emplace(glyph.Character, glyph);
    }
}
//-----------------------------------------------------------------------
SpriteFont::Impl::Impl(std::shared_ptr<GraphicsDevice> const& graphicsDeviceIn,
    std::shared_ptr<TrueTypeFont> const& fontIn,
    std::uint32_t defaultCharacterIn,
    std::int16_t lineSpacingIn)
    : graphicsDevice(graphicsDeviceIn)
    , font(fontIn)
    , defaultCharacter(defaultCharacterIn)
    , spacing(0)
    , lineSpacing(lineSpacingIn)
{
    POMDOG_ASSERT(font);

    pixelData.resize(TextureWidth * TextureHeight, 0);
    currentPoint = {1, 1};
    bottomY = 1;

    auto texture = std::make_shared<Texture2D>(graphicsDevice,
        TextureWidth, TextureHeight, false, SurfaceFormat::R8G8B8A8_UNorm);
    textures.push_back(texture);
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::PrepareFonts(std::string const& text)
{
    POMDOG_ASSERT(!text.empty());

    if (!graphicsDevice || !font) {
        return;
    }

    float fontSize = lineSpacing;

    bool needToFetchPixelData = false;

    auto fetchTextureData = [&] {
        if (needToFetchPixelData) {
            auto texture = textures.back();
            texture->SetData(ConvertTextureDataByteToByte4(pixelData.data(), pixelData.size()).data());
            needToFetchPixelData = false;
        }
    };

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd) {
        const auto character = utf8::next(textIter, textIterEnd);

        if (spriteFontMap.find(character) != std::end(spriteFontMap)) {
            continue;
        }

        auto glyph = font->RasterizeGlyph(character, fontSize, TextureWidth,
        [&](int glyphWidth, int glyphHeight, Point2D & pointOut, std::uint8_t* & output) {
            if (currentPoint.X + glyphWidth + 1 >= TextureWidth) {
                // advance to next row
                currentPoint.Y = bottomY;
                currentPoint.X = 1;
            }
            if (currentPoint.Y + glyphHeight + 1 >= TextureHeight) {
                fetchTextureData();
                std::fill(std::begin(pixelData), std::end(pixelData), 0);

                auto textureNew = std::make_shared<Texture2D>(graphicsDevice,
                    TextureWidth, TextureHeight, false, SurfaceFormat::R8G8B8A8_UNorm);
                textures.push_back(textureNew);
                currentPoint = {1, 1};
                bottomY = 1;
            }

            POMDOG_ASSERT(currentPoint.X + glyphWidth < TextureWidth);
            POMDOG_ASSERT(currentPoint.Y + glyphHeight < TextureHeight);

            pointOut = currentPoint;
            output = pixelData.data();
        });

        if (!glyph) {
            continue;
        }

        currentPoint.X = currentPoint.X + glyph->Subrect.Width + 1;
        bottomY = std::max(bottomY, currentPoint.Y + glyph->Subrect.Height + 1);

        POMDOG_ASSERT(!textures.empty() && textures.size() > 0);
        glyph->TexturePage = textures.size() - 1;

        spriteFontMap.emplace(glyph->Character, *glyph);
        needToFetchPixelData = true;
    }

    fetchTextureData();
}
//-----------------------------------------------------------------------
Vector2 SpriteFont::Impl::MeasureString(std::string const& text) const
{
    POMDOG_ASSERT(!text.empty());

    Vector2 result = Vector2::Zero;
    Vector2 currentPosition = Vector2::Zero;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = 0;
            currentPosition.Y -= lineSpacing;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            POMDOG_ASSERT(iter != std::end(spriteFontMap));
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        currentPosition.X += (glyph.XAdvance - spacing);

        result.X = std::max(result.X, currentPosition.X);
        result.Y = std::max(result.Y, currentPosition.Y);
    }

    return std::move(result);
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text, Vector2 const& position, Color const& color)
{
    if (text.empty()) {
        return;
    }

    if (textures.empty()) {
        return;
    }

    Vector2 currentPosition = position;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = position.X;
            currentPosition.Y -= lineSpacing;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            if (iter == std::end(spriteFontMap)) {
                continue;
            }
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        if (glyph.Subrect.Width > 0 && glyph.Subrect.Height > 0)
        {
            POMDOG_ASSERT(glyph.TexturePage >= 0);
            POMDOG_ASSERT(glyph.TexturePage < static_cast<int>(textures.size()));

            spriteBatch.Draw(textures[glyph.TexturePage],
                currentPosition + Vector2(glyph.XOffset, -glyph.YOffset),
                glyph.Subrect, color, 0.0f, Vector2{0.0f, 1.0f}, Vector2{1.0f, 1.0f});
        }

        currentPosition.X += (glyph.XAdvance - spacing);
    }
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    Vector2 const& scale)
{
    if (text.empty()) {
        return;
    }

    if (textures.empty()) {
        return;
    }

    Vector2 currentPosition = position;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = 0.0f;
            currentPosition.Y += lineSpacing * scale.Y;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            if (iter == std::end(spriteFontMap)) {
                continue;
            }
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        if (glyph.Subrect.Width > 0 && glyph.Subrect.Height > 0)
        {
            POMDOG_ASSERT(glyph.TexturePage >= 0);
            POMDOG_ASSERT(glyph.TexturePage < static_cast<int>(textures.size()));

            spriteBatch.Draw(textures[glyph.TexturePage],
                currentPosition + Vector2(glyph.XOffset, -glyph.YOffset) * scale,
                glyph.Subrect, color, 0.0f, Vector2{0.0f, 1.0f}, scale);
        }

        currentPosition.X += (glyph.XAdvance - spacing) * scale.X;
    }
}
//-----------------------------------------------------------------------
// MARK: - SpriteFont
//-----------------------------------------------------------------------
SpriteFont::SpriteFont(
    std::vector<std::shared_ptr<Texture2D>> && textures,
    std::vector<Detail::SpriteFonts::Glyph> const& glyphs,
    std::uint32_t defaultCharacter,
    std::int16_t spacing,
    std::int16_t lineSpacing)
    : impl(std::make_unique<Impl>(std::move(textures), glyphs, defaultCharacter, spacing, lineSpacing))
{
}
//-----------------------------------------------------------------------
SpriteFont::SpriteFont(
    std::shared_ptr<GraphicsDevice> const& graphicsDevice,
    std::shared_ptr<TrueTypeFont> const& font,
    std::uint32_t defaultCharacter,
    std::int16_t lineSpacing)
    : impl(std::make_unique<Impl>(graphicsDevice, font, defaultCharacter, lineSpacing))
{
}
//-----------------------------------------------------------------------
SpriteFont::~SpriteFont() = default;
//-----------------------------------------------------------------------
Vector2 SpriteFont::MeasureString(std::string const& utf8String) const
{
    if (utf8String.empty()) {
        return Vector2::Zero;
    }
    return impl->MeasureString(utf8String);
}
//-----------------------------------------------------------------------
std::uint32_t SpriteFont::GetDefaultCharacter() const
{
    POMDOG_ASSERT(impl);
    return impl->defaultCharacter;
}
//-----------------------------------------------------------------------
void SpriteFont::SetDefaultCharacter(std::uint32_t character)
{
    POMDOG_ASSERT(impl);
    POMDOG_ASSERT(ContainsCharacter(character));
    impl->defaultCharacter = character;
}
//-----------------------------------------------------------------------
float SpriteFont::GetLineSpacing() const
{
    POMDOG_ASSERT(impl);
    return impl->lineSpacing;
}
//-----------------------------------------------------------------------
void SpriteFont::SetLineSpacing(float lineSpacingIn)
{
    POMDOG_ASSERT(impl);
    impl->lineSpacing = lineSpacingIn;
}
//-----------------------------------------------------------------------
bool SpriteFont::ContainsCharacter(std::uint32_t character) const
{
    POMDOG_ASSERT(impl);
    return impl->spriteFontMap.find(character) != std::end(impl->spriteFontMap);
}
//-----------------------------------------------------------------------
void SpriteFont::Begin(
    std::shared_ptr<GraphicsCommandList> const& commandList,
    SpriteBatchRenderer & spriteBatch,
    Matrix4x4 const& transformMatrix)
{
    POMDOG_ASSERT(impl);
    POMDOG_ASSERT(commandList);

    spriteBatch.Begin(commandList, transformMatrix);

//    spriteBatch.Begin(SpriteSortMode::Deferred, Matrix4x4::CreateRotationZ(rotation)
//        * Matrix4x4::CreateScale({scale, 1.0f})
//        * Matrix4x4::CreateTranslation({position, 0.0f})
//        * transformMatrix);
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text, Vector2 const& position, Color const& color)
{
    if (text.empty()) {
        return;
    }

    impl->PrepareFonts(text);
    impl->Draw(spriteBatch, text, position, color);
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(
    SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    float scale)
{
    this->Draw(spriteBatch, text, position, color,
        rotation, Vector2{scale, scale});
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(
    SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    Vector2 const& scale)
{
    if (text.empty()) {
        return;
    }

    impl->PrepareFonts(text);
    impl->Draw(spriteBatch, text, position, color,
        rotation, scale);
}
//-----------------------------------------------------------------------
void SpriteFont::End(SpriteBatchRenderer & spriteBatch)
{
    spriteBatch.End();
}
//-----------------------------------------------------------------------
} // namespace Pomdog
<commit_msg>Fix compiling error in experimental<commit_after>// Copyright (c) 2013-2015 mogemimi. Distributed under the MIT license.

#include "SpriteFont.hpp"
#include "TrueTypeFont.hpp"
#include "SpriteBatchRenderer.hpp"
#include "Pomdog/Math/Color.hpp"
#include "Pomdog/Math/Matrix4x4.hpp"
#include "Pomdog/Math/Vector2.hpp"
#include "Pomdog/Math/Vector3.hpp"
#include "Pomdog/Math/Radian.hpp"
#include "Pomdog/Graphics/Texture2D.hpp"
#include "Pomdog/Utility/Assert.hpp"

#ifndef _MSC_VER
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
#endif
#include <utfcpp/source/utf8.h>
#ifndef _MSC_VER
#pragma clang diagnostic pop
#endif

#include <unordered_map>

namespace Pomdog {
namespace {

static std::vector<std::uint8_t> ConvertTextureDataByteToByte4(std::uint8_t const* source, size_t size)
{
    std::vector<std::uint8_t> output;
    output.reserve(size * 4);

    for (size_t i = 0; i < size; ++i) {
        output.push_back(255);
        output.push_back(255);
        output.push_back(255);
        output.push_back(source[i]);
    }
    return std::move(output);
}

} // unnamed namespace
//-----------------------------------------------------------------------
// MARK: - SpriteFont::Impl
//-----------------------------------------------------------------------
class SpriteFont::Impl {
public:
    typedef Detail::SpriteFonts::Glyph Glyph;

    static constexpr int TextureWidth = 512;
    static constexpr int TextureHeight = 512;

    std::unordered_map<std::uint32_t, Glyph> spriteFontMap;

    std::uint32_t defaultCharacter;
    float lineSpacing;
    std::uint16_t spacing;

    Impl(std::vector<std::shared_ptr<Texture2D>> && textures,
        std::vector<Detail::SpriteFonts::Glyph> const& glyphs,
        std::uint32_t defaultCharacter,
        std::int16_t spacing,
        std::int16_t lineSpacing);

    Impl(std::shared_ptr<GraphicsDevice> const& graphicsDevice,
        std::shared_ptr<TrueTypeFont> const& font,
        std::uint32_t defaultCharacter,
        std::int16_t lineSpacing);

    Vector2 MeasureString(std::string const& text) const;

    void Draw(
        SpriteBatchRenderer & spriteBatch,
        std::string const& text,
        Vector2 const& position,
        Color const& color);

    void Draw(
        SpriteBatchRenderer & spriteBatch,
        std::string const& text,
        Vector2 const& position,
        Color const& color,
        Radian<float> const& rotation,
        //Vector2 const& originPivot,
        Vector2 const& scale);

    void PrepareFonts(std::string const& text);

private:
    std::vector<std::shared_ptr<Texture2D>> textures;
    std::shared_ptr<GraphicsDevice> graphicsDevice;
    std::shared_ptr<TrueTypeFont> font;
    std::vector<std::uint8_t> pixelData;
    Point2D currentPoint;
    int bottomY;
};
constexpr int SpriteFont::Impl::TextureWidth;
constexpr int SpriteFont::Impl::TextureHeight;
//-----------------------------------------------------------------------
SpriteFont::Impl::Impl(std::vector<std::shared_ptr<Texture2D>> && texturesIn,
    std::vector<Detail::SpriteFonts::Glyph> const& glyphsIn,
    std::uint32_t defaultCharacterIn, std::int16_t spacingIn, std::int16_t lineSpacingIn)
    : textures(std::move(texturesIn))
    , defaultCharacter(defaultCharacterIn)
    , spacing(spacingIn)
    , lineSpacing(lineSpacingIn)
{
    for (auto & glyph: glyphsIn) {
        spriteFontMap.emplace(glyph.Character, glyph);
    }
}
//-----------------------------------------------------------------------
SpriteFont::Impl::Impl(std::shared_ptr<GraphicsDevice> const& graphicsDeviceIn,
    std::shared_ptr<TrueTypeFont> const& fontIn,
    std::uint32_t defaultCharacterIn,
    std::int16_t lineSpacingIn)
    : graphicsDevice(graphicsDeviceIn)
    , font(fontIn)
    , defaultCharacter(defaultCharacterIn)
    , spacing(0)
    , lineSpacing(lineSpacingIn)
{
    POMDOG_ASSERT(font);

    pixelData.resize(TextureWidth * TextureHeight, 0);
    currentPoint = {1, 1};
    bottomY = 1;

    auto texture = std::make_shared<Texture2D>(graphicsDevice,
        TextureWidth, TextureHeight, false, SurfaceFormat::R8G8B8A8_UNorm);
    textures.push_back(texture);
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::PrepareFonts(std::string const& text)
{
    POMDOG_ASSERT(!text.empty());

    if (!graphicsDevice || !font) {
        return;
    }

    float fontSize = lineSpacing;

    bool needToFetchPixelData = false;

    auto fetchTextureData = [&] {
        if (needToFetchPixelData) {
            auto texture = textures.back();
            texture->SetData(ConvertTextureDataByteToByte4(pixelData.data(), pixelData.size()).data());
            needToFetchPixelData = false;
        }
    };

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd) {
        const auto character = utf8::next(textIter, textIterEnd);

        if (spriteFontMap.find(character) != std::end(spriteFontMap)) {
            continue;
        }

        auto glyph = font->RasterizeGlyph(character, fontSize, TextureWidth,
        [&](int glyphWidth, int glyphHeight, Point2D & pointOut, std::uint8_t* & output) {
            if (currentPoint.X + glyphWidth + 1 >= TextureWidth) {
                // advance to next row
                currentPoint.Y = bottomY;
                currentPoint.X = 1;
            }
            if (currentPoint.Y + glyphHeight + 1 >= TextureHeight) {
                fetchTextureData();
                std::fill(std::begin(pixelData), std::end(pixelData), 0);

                auto textureNew = std::make_shared<Texture2D>(graphicsDevice,
                    TextureWidth, TextureHeight, false, SurfaceFormat::R8G8B8A8_UNorm);
                textures.push_back(textureNew);
                currentPoint = {1, 1};
                bottomY = 1;
            }

            POMDOG_ASSERT(currentPoint.X + glyphWidth < TextureWidth);
            POMDOG_ASSERT(currentPoint.Y + glyphHeight < TextureHeight);

            pointOut = currentPoint;
            output = pixelData.data();
        });

        if (!glyph) {
            continue;
        }

        currentPoint.X = currentPoint.X + glyph->Subrect.Width + 1;
        bottomY = std::max(bottomY, currentPoint.Y + glyph->Subrect.Height + 1);

        POMDOG_ASSERT(!textures.empty() && textures.size() > 0);
        glyph->TexturePage = textures.size() - 1;

        spriteFontMap.emplace(glyph->Character, *glyph);
        needToFetchPixelData = true;
    }

    fetchTextureData();
}
//-----------------------------------------------------------------------
Vector2 SpriteFont::Impl::MeasureString(std::string const& text) const
{
    POMDOG_ASSERT(!text.empty());

    Vector2 result = Vector2::Zero;
    Vector2 currentPosition = Vector2::Zero;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = 0;
            currentPosition.Y -= lineSpacing;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            POMDOG_ASSERT(iter != std::end(spriteFontMap));
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        currentPosition.X += (glyph.XAdvance - spacing);

        result.X = std::max(result.X, currentPosition.X);
        result.Y = std::max(result.Y, currentPosition.Y);
    }

    return std::move(result);
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text, Vector2 const& position, Color const& color)
{
    if (text.empty()) {
        return;
    }

    if (textures.empty()) {
        return;
    }

    Vector2 currentPosition = position;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = position.X;
            currentPosition.Y -= lineSpacing;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            if (iter == std::end(spriteFontMap)) {
                continue;
            }
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        if (glyph.Subrect.Width > 0 && glyph.Subrect.Height > 0)
        {
            POMDOG_ASSERT(glyph.TexturePage >= 0);
            POMDOG_ASSERT(glyph.TexturePage < static_cast<int>(textures.size()));

            spriteBatch.Draw(textures[glyph.TexturePage],
                currentPosition + Vector2(glyph.XOffset, -glyph.YOffset),
                glyph.Subrect, color, 0.0f, Vector2{0.0f, 1.0f}, Vector2{1.0f, 1.0f});
        }

        currentPosition.X += (glyph.XAdvance - spacing);
    }
}
//-----------------------------------------------------------------------
void SpriteFont::Impl::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    Vector2 const& scale)
{
    if (text.empty()) {
        return;
    }

    if (textures.empty()) {
        return;
    }

    Vector2 currentPosition = position;

    auto textIter = std::begin(text);
    auto textIterEnd = std::end(text);

    while (textIter != textIterEnd)
    {
        const auto character = utf8::next(textIter, textIterEnd);

        if (character == U'\n') {
            currentPosition.X = 0.0f;
            currentPosition.Y += lineSpacing * scale.Y;
            continue;
        }

        auto iter = spriteFontMap.find(character);
        if (iter == std::end(spriteFontMap)) {
            iter = spriteFontMap.find(defaultCharacter);
            if (iter == std::end(spriteFontMap)) {
                continue;
            }
        }

        POMDOG_ASSERT(iter != std::end(spriteFontMap));
        auto const & glyph = iter->second;

        if (glyph.Subrect.Width > 0 && glyph.Subrect.Height > 0)
        {
            POMDOG_ASSERT(glyph.TexturePage >= 0);
            POMDOG_ASSERT(glyph.TexturePage < static_cast<int>(textures.size()));

            spriteBatch.Draw(textures[glyph.TexturePage],
                currentPosition + Vector2(glyph.XOffset, -glyph.YOffset) * scale,
                glyph.Subrect, color, 0.0f, Vector2{0.0f, 1.0f}, scale);
        }

        currentPosition.X += (glyph.XAdvance - spacing) * scale.X;
    }
}
//-----------------------------------------------------------------------
// MARK: - SpriteFont
//-----------------------------------------------------------------------
SpriteFont::SpriteFont(
    std::vector<std::shared_ptr<Texture2D>> && textures,
    std::vector<Detail::SpriteFonts::Glyph> const& glyphs,
    std::uint32_t defaultCharacter,
    std::int16_t spacing,
    std::int16_t lineSpacing)
    : impl(std::make_unique<Impl>(std::move(textures), glyphs, defaultCharacter, spacing, lineSpacing))
{
}
//-----------------------------------------------------------------------
SpriteFont::SpriteFont(
    std::shared_ptr<GraphicsDevice> const& graphicsDevice,
    std::shared_ptr<TrueTypeFont> const& font,
    std::uint32_t defaultCharacter,
    std::int16_t lineSpacing)
    : impl(std::make_unique<Impl>(graphicsDevice, font, defaultCharacter, lineSpacing))
{
}
//-----------------------------------------------------------------------
SpriteFont::~SpriteFont() = default;
//-----------------------------------------------------------------------
Vector2 SpriteFont::MeasureString(std::string const& utf8String) const
{
    if (utf8String.empty()) {
        return Vector2::Zero;
    }
    return impl->MeasureString(utf8String);
}
//-----------------------------------------------------------------------
std::uint32_t SpriteFont::GetDefaultCharacter() const
{
    POMDOG_ASSERT(impl);
    return impl->defaultCharacter;
}
//-----------------------------------------------------------------------
void SpriteFont::SetDefaultCharacter(std::uint32_t character)
{
    POMDOG_ASSERT(impl);
    POMDOG_ASSERT(ContainsCharacter(character));
    impl->defaultCharacter = character;
}
//-----------------------------------------------------------------------
float SpriteFont::GetLineSpacing() const
{
    POMDOG_ASSERT(impl);
    return impl->lineSpacing;
}
//-----------------------------------------------------------------------
void SpriteFont::SetLineSpacing(float lineSpacingIn)
{
    POMDOG_ASSERT(impl);
    impl->lineSpacing = lineSpacingIn;
}
//-----------------------------------------------------------------------
bool SpriteFont::ContainsCharacter(std::uint32_t character) const
{
    POMDOG_ASSERT(impl);
    return impl->spriteFontMap.find(character) != std::end(impl->spriteFontMap);
}
//-----------------------------------------------------------------------
void SpriteFont::Begin(
    std::shared_ptr<GraphicsCommandList> const& commandList,
    SpriteBatchRenderer & spriteBatch,
    Matrix4x4 const& transformMatrix)
{
    POMDOG_ASSERT(impl);
    POMDOG_ASSERT(commandList);

    spriteBatch.Begin(commandList, transformMatrix);

//    spriteBatch.Begin(SpriteSortMode::Deferred, Matrix4x4::CreateRotationZ(rotation)
//        * Matrix4x4::CreateScale({scale, 1.0f})
//        * Matrix4x4::CreateTranslation({position, 0.0f})
//        * transformMatrix);
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(SpriteBatchRenderer & spriteBatch,
    std::string const& text, Vector2 const& position, Color const& color)
{
    if (text.empty()) {
        return;
    }

    impl->PrepareFonts(text);
    impl->Draw(spriteBatch, text, position, color);
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(
    SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    float scale)
{
    this->Draw(spriteBatch, text, position, color,
        rotation, Vector2{scale, scale});
}
//-----------------------------------------------------------------------
void SpriteFont::Draw(
    SpriteBatchRenderer & spriteBatch,
    std::string const& text,
    Vector2 const& position,
    Color const& color,
    Radian<float> const& rotation,
    //Vector2 const& originPivot,
    Vector2 const& scale)
{
    if (text.empty()) {
        return;
    }

    impl->PrepareFonts(text);
    impl->Draw(spriteBatch, text, position, color,
        rotation, scale);
}
//-----------------------------------------------------------------------
void SpriteFont::End(SpriteBatchRenderer & spriteBatch)
{
    spriteBatch.End();
}
//-----------------------------------------------------------------------
} // namespace Pomdog
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details

#include <visionaray/result_record.h>
#include <visionaray/simple_buffer_rt.h>
#include <visionaray/scheduler.h>

#include <gtest/gtest.h>

using namespace visionaray;

//-------------------------------------------------------------------------------------------------
// Simple kernels that store result in render target
// Test if pixel access works as expected
//

// kernel returns a color
template <typename R, typename RT>
void test_pixel_access_color(
        R       /* */,
        RT&     rt
        )
{
    // dummies
    mat4 mv;
    mat4 pr;
    recti vp(0, 0, 1, 1);

    auto sparams = make_sched_params(pixel_sampler::uniform_type{}, mv, pr, vp, rt);

    simple_sched<ray> sched;

    sched.frame([&](R r) -> typename RT::color_type
    {
        using C = typename RT::color_type;
        return C(0.5f);
    }, sparams);
}

// kernel returns a result record
template <typename R, typename RT>
void test_pixel_access_result_record(
        R       /* */,
        RT&     rt
        )
{
    using S = typename R::scalar_type;

    // dummies
    mat4 mv;
    mat4 pr;
    recti vp(0, 0, 1, 1);

    auto sparams = make_sched_params(pixel_sampler::uniform_type{}, mv, pr, vp, rt);

    simple_sched<ray> sched;

    sched.frame([&](R r) -> result_record<S>
    {
        result_record<S> result;
        result.color = typename result_record<S>::color_type(0.4f);
        return result;
    }, sparams);
}

//-------------------------------------------------------------------------------------------------
// Test if pixel access to render targets works
//

TEST(RenderTarget, PixelFormats)
{
    simple_buffer_rt<PF_RGB32F, PF_UNSPECIFIED> rt_RGB32F;
    rt_RGB32F.resize(1, 1);

    simple_buffer_rt<PF_RGBA32F, PF_UNSPECIFIED> rt_RGBA32F;
    rt_RGBA32F.resize(1, 1);

    // Color access, color: RGB32F, depth: UNSPECIFIED ------------------------

    test_pixel_access_color(ray(), rt_RGB32F);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].x, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].y, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].z, 0.5f);

    // Color access, color: RGBA32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_color(ray(), rt_RGBA32F);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].x, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].y, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].z, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].w, 0.5f);

    // Result record, color: RGB32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_result_record(ray(), rt_RGB32F);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].x, 0.16); // alpha multiplication!
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].y, 0.16);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].z, 0.16);

    // Result record, color: RGB32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_result_record(ray(), rt_RGBA32F);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].x, 0.4f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].y, 0.4f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].z, 0.4f);
}
<commit_msg>Silence some unnecessary warnings<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details

#include <visionaray/result_record.h>
#include <visionaray/simple_buffer_rt.h>
#include <visionaray/scheduler.h>

#include <gtest/gtest.h>

using namespace visionaray;

//-------------------------------------------------------------------------------------------------
// Simple kernels that store result in render target
// Test if pixel access works as expected
//

// kernel returns a color
template <typename R, typename RT>
void test_pixel_access_color(
        R       /* */,
        RT&     rt
        )
{
    // dummies
    mat4 mv = mat4::identity();
    mat4 pr = mat4::identity();
    recti vp(0, 0, 1, 1);

    auto sparams = make_sched_params(pixel_sampler::uniform_type{}, mv, pr, vp, rt);

    simple_sched<ray> sched;

    sched.frame([&](R) -> typename RT::color_type
    {
        using C = typename RT::color_type;
        return C(0.5f);
    }, sparams);
}

// kernel returns a result record
template <typename R, typename RT>
void test_pixel_access_result_record(
        R       /* */,
        RT&     rt
        )
{
    using S = typename R::scalar_type;

    // dummies
    mat4 mv = mat4::identity();
    mat4 pr = mat4::identity();
    recti vp(0, 0, 1, 1);

    auto sparams = make_sched_params(pixel_sampler::uniform_type{}, mv, pr, vp, rt);

    simple_sched<ray> sched;

    sched.frame([&](R) -> result_record<S>
    {
        result_record<S> result;
        result.color = typename result_record<S>::color_type(0.4f);
        return result;
    }, sparams);
}

//-------------------------------------------------------------------------------------------------
// Test if pixel access to render targets works
//

TEST(RenderTarget, PixelFormats)
{
    simple_buffer_rt<PF_RGB32F, PF_UNSPECIFIED> rt_RGB32F;
    rt_RGB32F.resize(1, 1);

    simple_buffer_rt<PF_RGBA32F, PF_UNSPECIFIED> rt_RGBA32F;
    rt_RGBA32F.resize(1, 1);

    // Color access, color: RGB32F, depth: UNSPECIFIED ------------------------

    test_pixel_access_color(ray(), rt_RGB32F);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].x, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].y, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].z, 0.5f);

    // Color access, color: RGBA32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_color(ray(), rt_RGBA32F);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].x, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].y, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].z, 0.5f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].w, 0.5f);

    // Result record, color: RGB32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_result_record(ray(), rt_RGB32F);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].x, 0.16); // alpha multiplication!
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].y, 0.16);
    EXPECT_FLOAT_EQ(rt_RGB32F.color()[0].z, 0.16);

    // Result record, color: RGB32F, depth: UNSPECIFIED -----------------------

    test_pixel_access_result_record(ray(), rt_RGBA32F);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].x, 0.4f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].y, 0.4f);
    EXPECT_FLOAT_EQ(rt_RGBA32F.color()[0].z, 0.4f);
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/framework/executor.h"

#include <set>

#include "gflags/gflags.h"
#include "paddle/fluid/framework/channel.h"
#include "paddle/fluid/framework/feed_fetch_method.h"
#include "paddle/fluid/framework/feed_fetch_type.h"
#include "paddle/fluid/framework/lod_rank_table.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/platform/place.h"

DECLARE_bool(benchmark);
DEFINE_bool(check_nan_inf, false,
            "Checking whether operator produce NAN/INF or not. It will be "
            "extremely slow so please use this flag wisely.");

namespace paddle {
namespace framework {

Executor::Executor(const platform::Place& place) : place_(place) {}

static void CreateTensor(Variable* var, proto::VarType::Type var_type) {
  if (var_type == proto::VarType::LOD_TENSOR) {
    var->GetMutable<LoDTensor>();
  } else if (var_type == proto::VarType::SELECTED_ROWS) {
    var->GetMutable<SelectedRows>();
  } else if (var_type == proto::VarType::FEED_MINIBATCH) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarType::FETCH_LIST) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarType::STEP_SCOPES) {
    var->GetMutable<std::vector<framework::Scope>>();
  } else if (var_type == proto::VarType::LOD_RANK_TABLE) {
    var->GetMutable<LoDRankTable>();
  } else if (var_type == proto::VarType::LOD_TENSOR_ARRAY) {
    var->GetMutable<LoDTensorArray>();
  } else if (var_type == proto::VarType::PLACE_LIST) {
    var->GetMutable<platform::PlaceList>();
  } else if (var_type == proto::VarType::READER) {
    var->GetMutable<ReaderHolder>();
  } else if (var_type == proto::VarType::CHANNEL) {
    var->GetMutable<ChannelHolder>();
  } else if (var_type == proto::VarType::RAW) {
    // GetMutable will be called in operator
  } else {
    PADDLE_THROW(
        "Variable type %d is not in "
        "[LOD_TENSOR, SELECTED_ROWS, FEED_MINIBATCH, FETCH_LIST, "
        "LOD_RANK_TABLE, PLACE_LIST, READER, CHANNEL, RAW]",
        var_type);
  }
}

static void CheckTensorNANOrInf(const std::string& name,
                                const framework::Tensor& tensor) {
  if (tensor.memory_size() == 0) {
    return;
  }
  if (tensor.type().hash_code() != typeid(float).hash_code() &&
      tensor.type().hash_code() != typeid(double).hash_code()) {
    return;
  }
  PADDLE_ENFORCE(!framework::TensorContainsInf(tensor),
                 "Tensor %s contains Inf", name);
  PADDLE_ENFORCE(!framework::TensorContainsNAN(tensor),
                 "Tensor %s contains NAN", name);
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id,
                   bool create_local_scope, bool create_vars) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_LT(static_cast<size_t>(block_id), pdesc.Size());
  auto& block = pdesc.Block(block_id);

  Scope* local_scope = scope;
  if (create_vars) {
    if (create_local_scope) {
      local_scope = &scope->NewScope();
      for (auto& var : block.AllVars()) {
        if (var->Name() == framework::kEmptyVarName) {
          continue;
        }

        if (var->Persistable()) {
          auto* ptr = scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " global, which pointer is " << ptr;
        } else {
          auto* ptr = local_scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " locally, which pointer is " << ptr;
        }
      }
    } else {
      for (auto& var : block.AllVars()) {
        auto* ptr = local_scope->Var(var->Name());
        CreateTensor(ptr, var->GetType());
        VLOG(3) << "Create variable " << var->Name() << ", which pointer is "
                << ptr;
      }
    }  // if (create_local_scope)
  }    // if (create_vars)

  for (auto& op_desc : block.AllOps()) {
    auto op = paddle::framework::OpRegistry::CreateOp(*op_desc);

    VLOG(3) << place_ << " " << op->DebugStringEx(local_scope);
    op->Run(*local_scope, place_);

    if (FLAGS_benchmark) {
      VLOG(2) << "Memory used after operator " + op->Type() + " running: "
              << memory::memory_usage(place_);
    }
    if (FLAGS_check_nan_inf) {
      for (auto& vname : op->OutputVars(true)) {
        auto* var = local_scope->FindVar(vname);
        if (var == nullptr) continue;
        if (var->IsType<framework::LoDTensor>()) {
          CheckTensorNANOrInf(vname, var->Get<framework::LoDTensor>());
        }
      }
    }
  }
  if (create_vars && create_local_scope) {
    scope->DeleteScope(local_scope);
  }
  if (FLAGS_benchmark) {
    VLOG(2) << "-------------------------------------------------------";
    VLOG(2) << "Memory used after deleting local scope: "
            << memory::memory_usage(place_);
    VLOG(2) << "-------------------------------------------------------";
  }
}

// Check whether the block already has feed operators and feed_holder.
// Return false if the block does not have any feed operators.
// If some feed operators have been prepended to the block, check that
// the info contained in these feed operators matches the feed_targets
// and feed_holder_name. Raise exception when any mismatch is found.
// Return true if the block has feed operators and holder of matching info.
static bool has_feed_operators(
    BlockDesc* block, std::map<std::string, const LoDTensor*>& feed_targets,
    const std::string& feed_holder_name) {
  size_t feed_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      feed_count++;
      PADDLE_ENFORCE_EQ(op->Input("X")[0], feed_holder_name,
                        "Input to feed op should be '%s'", feed_holder_name);
      std::string feed_target_name = op->Output("Out")[0];
      PADDLE_ENFORCE(
          feed_targets.find(feed_target_name) != feed_targets.end(),
          "Feed operator output name '%s' cannot be found in 'feed_targets'",
          feed_target_name);
    }
  }

  if (feed_count > 0) {
    PADDLE_ENFORCE_EQ(
        feed_count, feed_targets.size(),
        "The number of feed operators should match 'feed_targets'");

    // When feed operator are present, so should be feed_holder
    auto var = block->FindVar(feed_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            feed_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FEED_MINIBATCH,
                      "'%s' variable should be 'FEED_MINIBATCH' type",
                      feed_holder_name);
  }

  return feed_count > 0;
}

// Check whether the block already has fetch operators and fetch_holder.
// Return false if the block does not have any fetch operators.
// If some fetch operators have been appended to the block, check that
// the info contained in these fetch operators matches the fetch_targets
// and fetch_holder_name. Raise exception when any mismatch is found.
// Return true if the block has fetch operators and holder of matching info.
static bool has_fetch_operators(
    BlockDesc* block, std::map<std::string, LoDTensor*>& fetch_targets,
    const std::string& fetch_holder_name) {
  size_t fetch_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      fetch_count++;
      PADDLE_ENFORCE_EQ(op->Output("Out")[0], fetch_holder_name,
                        "Output of fetch op should be '%s'", fetch_holder_name);
      std::string fetch_target_name = op->Input("X")[0];
      PADDLE_ENFORCE(
          fetch_targets.find(fetch_target_name) != fetch_targets.end(),
          "Fetch operator input name '%s' cannot be found in 'fetch_targets'",
          fetch_target_name);
    }
  }

  if (fetch_count > 0) {
    PADDLE_ENFORCE_EQ(
        fetch_count, fetch_targets.size(),
        "The number of fetch operators should match 'fetch_targets'");

    // When fetch operator are present, so should be fetch_holder
    auto var = block->FindVar(fetch_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            fetch_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FETCH_LIST,
                      "'%s' variable should be 'FETCH_LIST' type",
                      fetch_holder_name);
  }

  return fetch_count > 0;
}

void Executor::Run(const ProgramDesc& program, Scope* scope,
                   std::map<std::string, const LoDTensor*>& feed_targets,
                   std::map<std::string, LoDTensor*>& fetch_targets,
                   const std::string& feed_holder_name,
                   const std::string& fetch_holder_name) {
  auto* copy_program = new ProgramDesc(program);
  auto* global_block = copy_program->MutableBlock(0);

  if (!has_feed_operators(global_block, feed_targets, feed_holder_name)) {
    // create feed_holder variable
    auto* feed_holder = global_block->Var(feed_holder_name);
    feed_holder->SetType(proto::VarType::FEED_MINIBATCH);
    feed_holder->SetPersistable(true);

    int i = 0;
    for (auto& feed_target : feed_targets) {
      std::string var_name = feed_target.first;
      VLOG(3) << "feed target's name: " << var_name;

      // prepend feed op
      auto* op = global_block->PrependOp();
      op->SetType(kFeedOpType);
      op->SetInput("X", {feed_holder_name});
      op->SetOutput("Out", {var_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  // map the data of feed_targets to feed_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      std::string feed_target_name = op->Output("Out")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      SetFeedVariable(scope, *feed_targets[feed_target_name], feed_holder_name,
                      idx);
    }
  }

  if (!has_fetch_operators(global_block, fetch_targets, fetch_holder_name)) {
    // create fetch_holder variable
    auto* fetch_holder = global_block->Var(fetch_holder_name);
    fetch_holder->SetType(proto::VarType::FETCH_LIST);
    fetch_holder->SetPersistable(true);

    int i = 0;
    for (auto& fetch_target : fetch_targets) {
      std::string var_name = fetch_target.first;
      VLOG(3) << "fetch target's name: " << var_name;

      // append fetch op
      auto* op = global_block->AppendOp();
      op->SetType(kFetchOpType);
      op->SetInput("X", {var_name});
      op->SetOutput("Out", {fetch_holder_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  Run(*copy_program, scope, 0, true, true);

  // obtain the data of fetch_targets from fetch_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      std::string fetch_target_name = op->Input("X")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      *fetch_targets[fetch_target_name] =
          GetFetchVariable(*scope, fetch_holder_name, idx);
    }
  }

  delete copy_program;
}

}  // namespace framework
}  // namespace paddle
<commit_msg>Add log before op Run<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/framework/executor.h"

#include <set>

#include "gflags/gflags.h"
#include "paddle/fluid/framework/channel.h"
#include "paddle/fluid/framework/feed_fetch_method.h"
#include "paddle/fluid/framework/feed_fetch_type.h"
#include "paddle/fluid/framework/lod_rank_table.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/platform/place.h"

DECLARE_bool(benchmark);
DEFINE_bool(check_nan_inf, false,
            "Checking whether operator produce NAN/INF or not. It will be "
            "extremely slow so please use this flag wisely.");

namespace paddle {
namespace framework {

Executor::Executor(const platform::Place& place) : place_(place) {}

static void CreateTensor(Variable* var, proto::VarType::Type var_type) {
  if (var_type == proto::VarType::LOD_TENSOR) {
    var->GetMutable<LoDTensor>();
  } else if (var_type == proto::VarType::SELECTED_ROWS) {
    var->GetMutable<SelectedRows>();
  } else if (var_type == proto::VarType::FEED_MINIBATCH) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarType::FETCH_LIST) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarType::STEP_SCOPES) {
    var->GetMutable<std::vector<framework::Scope>>();
  } else if (var_type == proto::VarType::LOD_RANK_TABLE) {
    var->GetMutable<LoDRankTable>();
  } else if (var_type == proto::VarType::LOD_TENSOR_ARRAY) {
    var->GetMutable<LoDTensorArray>();
  } else if (var_type == proto::VarType::PLACE_LIST) {
    var->GetMutable<platform::PlaceList>();
  } else if (var_type == proto::VarType::READER) {
    var->GetMutable<ReaderHolder>();
  } else if (var_type == proto::VarType::CHANNEL) {
    var->GetMutable<ChannelHolder>();
  } else if (var_type == proto::VarType::RAW) {
    // GetMutable will be called in operator
  } else {
    PADDLE_THROW(
        "Variable type %d is not in "
        "[LOD_TENSOR, SELECTED_ROWS, FEED_MINIBATCH, FETCH_LIST, "
        "LOD_RANK_TABLE, PLACE_LIST, READER, CHANNEL, RAW]",
        var_type);
  }
}

static void CheckTensorNANOrInf(const std::string& name,
                                const framework::Tensor& tensor) {
  if (tensor.memory_size() == 0) {
    return;
  }
  if (tensor.type().hash_code() != typeid(float).hash_code() &&
      tensor.type().hash_code() != typeid(double).hash_code()) {
    return;
  }
  PADDLE_ENFORCE(!framework::TensorContainsInf(tensor),
                 "Tensor %s contains Inf", name);
  PADDLE_ENFORCE(!framework::TensorContainsNAN(tensor),
                 "Tensor %s contains NAN", name);
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id,
                   bool create_local_scope, bool create_vars) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_LT(static_cast<size_t>(block_id), pdesc.Size());
  auto& block = pdesc.Block(block_id);

  Scope* local_scope = scope;
  if (create_vars) {
    if (create_local_scope) {
      local_scope = &scope->NewScope();
      for (auto& var : block.AllVars()) {
        if (var->Name() == framework::kEmptyVarName) {
          continue;
        }

        if (var->Persistable()) {
          auto* ptr = scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " global, which pointer is " << ptr;
        } else {
          auto* ptr = local_scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " locally, which pointer is " << ptr;
        }
      }
    } else {
      for (auto& var : block.AllVars()) {
        auto* ptr = local_scope->Var(var->Name());
        CreateTensor(ptr, var->GetType());
        VLOG(3) << "Create variable " << var->Name() << ", which pointer is "
                << ptr;
      }
    }  // if (create_local_scope)
  }    // if (create_vars)

  for (auto& op_desc : block.AllOps()) {
    auto op = paddle::framework::OpRegistry::CreateOp(*op_desc);

    VLOG(4) << place_ << " " << op->DebugStringEx(local_scope);
    op->Run(*local_scope, place_);
    VLOG(3) << place_ << " " << op->DebugStringEx(local_scope);

    if (FLAGS_benchmark) {
      VLOG(2) << "Memory used after operator " + op->Type() + " running: "
              << memory::memory_usage(place_);
    }
    if (FLAGS_check_nan_inf) {
      for (auto& vname : op->OutputVars(true)) {
        auto* var = local_scope->FindVar(vname);
        if (var == nullptr) continue;
        if (var->IsType<framework::LoDTensor>()) {
          CheckTensorNANOrInf(vname, var->Get<framework::LoDTensor>());
        }
      }
    }
  }
  if (create_vars && create_local_scope) {
    scope->DeleteScope(local_scope);
  }
  if (FLAGS_benchmark) {
    VLOG(2) << "-------------------------------------------------------";
    VLOG(2) << "Memory used after deleting local scope: "
            << memory::memory_usage(place_);
    VLOG(2) << "-------------------------------------------------------";
  }
}

// Check whether the block already has feed operators and feed_holder.
// Return false if the block does not have any feed operators.
// If some feed operators have been prepended to the block, check that
// the info contained in these feed operators matches the feed_targets
// and feed_holder_name. Raise exception when any mismatch is found.
// Return true if the block has feed operators and holder of matching info.
static bool has_feed_operators(
    BlockDesc* block, std::map<std::string, const LoDTensor*>& feed_targets,
    const std::string& feed_holder_name) {
  size_t feed_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      feed_count++;
      PADDLE_ENFORCE_EQ(op->Input("X")[0], feed_holder_name,
                        "Input to feed op should be '%s'", feed_holder_name);
      std::string feed_target_name = op->Output("Out")[0];
      PADDLE_ENFORCE(
          feed_targets.find(feed_target_name) != feed_targets.end(),
          "Feed operator output name '%s' cannot be found in 'feed_targets'",
          feed_target_name);
    }
  }

  if (feed_count > 0) {
    PADDLE_ENFORCE_EQ(
        feed_count, feed_targets.size(),
        "The number of feed operators should match 'feed_targets'");

    // When feed operator are present, so should be feed_holder
    auto var = block->FindVar(feed_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            feed_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FEED_MINIBATCH,
                      "'%s' variable should be 'FEED_MINIBATCH' type",
                      feed_holder_name);
  }

  return feed_count > 0;
}

// Check whether the block already has fetch operators and fetch_holder.
// Return false if the block does not have any fetch operators.
// If some fetch operators have been appended to the block, check that
// the info contained in these fetch operators matches the fetch_targets
// and fetch_holder_name. Raise exception when any mismatch is found.
// Return true if the block has fetch operators and holder of matching info.
static bool has_fetch_operators(
    BlockDesc* block, std::map<std::string, LoDTensor*>& fetch_targets,
    const std::string& fetch_holder_name) {
  size_t fetch_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      fetch_count++;
      PADDLE_ENFORCE_EQ(op->Output("Out")[0], fetch_holder_name,
                        "Output of fetch op should be '%s'", fetch_holder_name);
      std::string fetch_target_name = op->Input("X")[0];
      PADDLE_ENFORCE(
          fetch_targets.find(fetch_target_name) != fetch_targets.end(),
          "Fetch operator input name '%s' cannot be found in 'fetch_targets'",
          fetch_target_name);
    }
  }

  if (fetch_count > 0) {
    PADDLE_ENFORCE_EQ(
        fetch_count, fetch_targets.size(),
        "The number of fetch operators should match 'fetch_targets'");

    // When fetch operator are present, so should be fetch_holder
    auto var = block->FindVar(fetch_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            fetch_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FETCH_LIST,
                      "'%s' variable should be 'FETCH_LIST' type",
                      fetch_holder_name);
  }

  return fetch_count > 0;
}

void Executor::Run(const ProgramDesc& program, Scope* scope,
                   std::map<std::string, const LoDTensor*>& feed_targets,
                   std::map<std::string, LoDTensor*>& fetch_targets,
                   const std::string& feed_holder_name,
                   const std::string& fetch_holder_name) {
  auto* copy_program = new ProgramDesc(program);
  auto* global_block = copy_program->MutableBlock(0);

  if (!has_feed_operators(global_block, feed_targets, feed_holder_name)) {
    // create feed_holder variable
    auto* feed_holder = global_block->Var(feed_holder_name);
    feed_holder->SetType(proto::VarType::FEED_MINIBATCH);
    feed_holder->SetPersistable(true);

    int i = 0;
    for (auto& feed_target : feed_targets) {
      std::string var_name = feed_target.first;
      VLOG(3) << "feed target's name: " << var_name;

      // prepend feed op
      auto* op = global_block->PrependOp();
      op->SetType(kFeedOpType);
      op->SetInput("X", {feed_holder_name});
      op->SetOutput("Out", {var_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  // map the data of feed_targets to feed_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      std::string feed_target_name = op->Output("Out")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      SetFeedVariable(scope, *feed_targets[feed_target_name], feed_holder_name,
                      idx);
    }
  }

  if (!has_fetch_operators(global_block, fetch_targets, fetch_holder_name)) {
    // create fetch_holder variable
    auto* fetch_holder = global_block->Var(fetch_holder_name);
    fetch_holder->SetType(proto::VarType::FETCH_LIST);
    fetch_holder->SetPersistable(true);

    int i = 0;
    for (auto& fetch_target : fetch_targets) {
      std::string var_name = fetch_target.first;
      VLOG(3) << "fetch target's name: " << var_name;

      // append fetch op
      auto* op = global_block->AppendOp();
      op->SetType(kFetchOpType);
      op->SetInput("X", {var_name});
      op->SetOutput("Out", {fetch_holder_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  Run(*copy_program, scope, 0, true, true);

  // obtain the data of fetch_targets from fetch_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      std::string fetch_target_name = op->Input("X")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      *fetch_targets[fetch_target_name] =
          GetFetchVariable(*scope, fetch_holder_name, idx);
    }
  }

  delete copy_program;
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/operators/prelu_op.h"
#include <string>

namespace paddle {
namespace operators {

class PReluOp : public framework::OperatorWithKernel {
 public:
  PReluOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
    std::string mode = ctx->Attrs().Get<std::string>("mode");

    auto x_dim = ctx->GetInputDim("X");
    PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should not be null");
    PADDLE_ENFORCE(ctx->HasInput("Alpha"), "Input(Alpha) should not be null");

    PADDLE_ENFORCE(ctx->HasOutput("Out"), "Output(Out) should not be null");
    if (mode == "all") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == 1,
                     "For mode 'all', size of weight Alpha must be one.");
    } else if (mode == "channel") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == x_dim[1],
                     "For channel-wise mode, size of weight Alpha must be "
                     "equal to the number of channels, should be %d",
                     x_dim[1]);
    } else if (mode == "element") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == product(x_dim),
                     "For element-wise mode, size of weight Alpha must be "
                     "equal to the number of input, should be %d",
                     product(x_dim));
    } else {
      PADDLE_THROW("Unkown mode %s", mode);
    }
    ctx->SetOutputDim("Out", x_dim);
    ctx->ShareLoD("X", /*->*/ "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::ToDataType(ctx.Input<Tensor>("X")->type()),
        platform::CPUPlace());
  }
};

class PReluOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "The input tensor of prelu operator.");
    AddInput("Alpha", "The alpha weight of prelu operator.");
    AddOutput("Out", "The output tensor of prelu operator.");
    AddComment(R"DOC(
PRelu Operator.
The equation is:
$$
f(x) =
\begin{cases}
\alpha * x, \quad  \text{if} \ x < 0 \\
x,         \qquad  \text{if} \ x >= 0
\end{cases}
$$
The input `X` can carry the LoD (Level of Details) information,
or not. And the output shares the LoD information with input `X`.
There are modes:
  all: all elements share same weight
  channel: elements in a channel share same weight
  element: each element has a weight
)DOC");
    AddAttr<std::string>("mode", "The mode for inputs to share weights.")
        .SetDefault("all");
  }
};

// The operator to calculate gradients of a prelu operator.
class PReluGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext *ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) must not be null.");
    PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")),
                   "Input(Out@GRAD) should not be null");
    auto x_grad_name = framework::GradVarName("X");
    auto alpha_grad_name = framework::GradVarName("Alpha");

    if (ctx->HasOutput(x_grad_name)) {
      ctx->SetOutputDim(x_grad_name, ctx->GetInputDim("X"));
    }
    if (ctx->HasOutput(alpha_grad_name)) {
      ctx->SetOutputDim(alpha_grad_name, ctx->GetInputDim("Alpha"));
    }
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::ToDataType(ctx.Input<Tensor>("X")->type()),
        platform::CPUPlace());
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OPERATOR(prelu, ops::PReluOp, ops::PReluOpMaker,
                  paddle::framework::DefaultGradOpDescMaker<true>);
REGISTER_OPERATOR(prelu_grad, ops::PReluGradOp);
REGISTER_OP_CPU_KERNEL(
    prelu, ops::PReluKernel<paddle::platform::CPUDeviceContext, float>);
REGISTER_OP_CPU_KERNEL(
    prelu_grad,
    ops::PReluGradKernel<paddle::platform::CPUDeviceContext, float>);
<commit_msg>add error_info prelu_op<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/operators/prelu_op.h"
#include <string>

namespace paddle {
namespace operators {

class PReluOp : public framework::OperatorWithKernel {
 public:
  PReluOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
    std::string mode = ctx->Attrs().Get<std::string>("mode");

    auto x_dim = ctx->GetInputDim("X");
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of PreluOp should not be null");
    PADDLE_ENFORCE(ctx->HasInput("Alpha"),
                   "Input(Alpha) of PreluOp should not be null");

    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of PreluOp should not be null");
    if (mode == "all") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == 1,
                     "For mode 'all', size of weight Alpha must be one.");
    } else if (mode == "channel") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == x_dim[1],
                     "For channel-wise mode, size of weight Alpha must be "
                     "equal to the number of channels, should be %d",
                     x_dim[1]);
    } else if (mode == "element") {
      PADDLE_ENFORCE(product(ctx->GetInputDim("Alpha")) == product(x_dim),
                     "For element-wise mode, size of weight Alpha must be "
                     "equal to the number of input, should be %d",
                     product(x_dim));
    } else {
      PADDLE_THROW("Unkown mode %s", mode);
    }
    ctx->SetOutputDim("Out", x_dim);
    ctx->ShareLoD("X", /*->*/ "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::ToDataType(ctx.Input<Tensor>("X")->type()),
        platform::CPUPlace());
  }
};

class PReluOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "The input tensor of prelu operator.");
    AddInput("Alpha", "The alpha weight of prelu operator.");
    AddOutput("Out", "The output tensor of prelu operator.");
    AddComment(R"DOC(
PRelu Operator.
The equation is:
$$
f(x) =
\begin{cases}
\alpha * x, \quad  \text{if} \ x < 0 \\
x,         \qquad  \text{if} \ x >= 0
\end{cases}
$$
The input `X` can carry the LoD (Level of Details) information,
or not. And the output shares the LoD information with input `X`.
There are modes:
  all: all elements share same weight
  channel: elements in a channel share same weight
  element: each element has a weight
)DOC");
    AddAttr<std::string>("mode", "The mode for inputs to share weights.")
        .SetDefault("all");
  }
};

// The operator to calculate gradients of a prelu operator.
class PReluGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext *ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) must not be null.");
    PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")),
                   "Input(Out@GRAD) should not be null");
    auto x_grad_name = framework::GradVarName("X");
    auto alpha_grad_name = framework::GradVarName("Alpha");

    if (ctx->HasOutput(x_grad_name)) {
      ctx->SetOutputDim(x_grad_name, ctx->GetInputDim("X"));
    }
    if (ctx->HasOutput(alpha_grad_name)) {
      ctx->SetOutputDim(alpha_grad_name, ctx->GetInputDim("Alpha"));
    }
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::ToDataType(ctx.Input<Tensor>("X")->type()),
        platform::CPUPlace());
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OPERATOR(prelu, ops::PReluOp, ops::PReluOpMaker,
                  paddle::framework::DefaultGradOpDescMaker<true>);
REGISTER_OPERATOR(prelu_grad, ops::PReluGradOp);
REGISTER_OP_CPU_KERNEL(
    prelu, ops::PReluKernel<paddle::platform::CPUDeviceContext, float>);
REGISTER_OP_CPU_KERNEL(
    prelu_grad,
    ops::PReluGradKernel<paddle::platform::CPUDeviceContext, float>);
<|endoftext|>


<commit_before>#include "code_it_pr2/robot_api.h"

#include "code_it/Say.h"
#include "code_it/AskMultipleChoice.h"
#include "code_it/DisplayMessage.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "rapid/display/display.h"
#include "rapid/pr2/pr2.h"
#include "rapid/sound/sound.h"
#include "ros/ros.h"
#include "std_msgs/Bool.h"

using code_it_pr2::RobotApi;
using rapid::display::MockDisplay;
using rapid::pr2::Pr2;
using rapid::sound::MockSound;
using rapid::sound::SoundPlay;
using ::testing::Return;

class RobotApiNodeTest : public ::testing::Test {
 public:
  RobotApiNodeTest()
      : nh_(),
        display_(),
        sound_(),
        pr2_(display_, sound_),
        api_(pr2_),
        say_srv_(
            nh_.advertiseService("code_it/api/say", &RobotApi::Say, &api_)),
        ask_mc_srv_(nh_.advertiseService("code_it/api/ask_multiple_choice",
                                         &RobotApi::AskMultipleChoice, &api_)),
        disp_msg_srv_(nh_.advertiseService("code_it/api/display_message",
                                           &RobotApi::DisplayMessage, &api_)),
        is_running_pub_(
            nh_.advertise<std_msgs::Bool>("code_it/is_program_running", 5)),
        is_running_sub_(nh_.subscribe("code_it/is_program_running", 10,
                                      &RobotApi::HandleProgramStopped, &api_)) {
  }

  void SetUp() {
    while (!IsNodeReady()) {
      ros::spinOnce();
    }
  }

 protected:
  bool IsNodeReady() {
    return is_running_pub_.getNumSubscribers() > 0 &&
           is_running_sub_.getNumPublishers() > 0;
  }

  bool WaitForMessage(int timeout) {
    std_msgs::BoolConstPtr msg = ros::topic::waitForMessage<std_msgs::Bool>(
        is_running_sub_.getTopic(), nh_, ros::Duration(timeout));
    if (msg.get() == NULL) {
      return false;
    } else {
      return true;
    }
  }

  ros::NodeHandle nh_;
  MockDisplay display_;
  MockSound sound_;
  Pr2 pr2_;
  RobotApi api_;
  ros::ServiceServer say_srv_;
  ros::ServiceServer ask_mc_srv_;
  ros::ServiceServer disp_msg_srv_;
  ros::Publisher is_running_pub_;
  ros::Subscriber is_running_sub_;
};

TEST_F(RobotApiNodeTest, TestCallsAreWiredUp) {
  EXPECT_CALL(sound_, Say("Hello world!"));
  bool on_time =
      ros::service::waitForService("code_it/api/say", ros::Duration(5));
  ASSERT_EQ(true, on_time);

  code_it::SayRequest req;
  req.text = "Hello world!";
  code_it::SayResponse res;
  bool success = ros::service::call("/code_it/api/say", req, res);
  EXPECT_EQ(true, success);
}

TEST_F(RobotApiNodeTest, TestScreenResetsOnProgramEnd) {
  EXPECT_CALL(display_, ShowDefault()).Times(0);
  std_msgs::Bool msg;
  msg.data = true;
  ros::Publisher is_running_pub =
      nh_.advertise<std_msgs::Bool>("code_it/is_program_running", 10);
  is_running_pub.publish(msg);
  bool success = WaitForMessage(5);

  EXPECT_CALL(display_, ShowDefault()).WillOnce(Return(true));
  msg.data = false;
  is_running_pub.publish(msg);
  success = WaitForMessage(5);
  EXPECT_EQ(true, success);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  ros::init(argc, argv, "robot_api_test");
  ros::AsyncSpinner spinner(1);
  spinner.start();
  int ret = RUN_ALL_TESTS();
  spinner.stop();
  ros::shutdown();
  return ret;
}
<commit_msg>Use a less flaky test.<commit_after>#include "code_it_pr2/robot_api.h"

#include "code_it/Say.h"
#include "code_it/AskMultipleChoice.h"
#include "code_it/DisplayMessage.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "rapid/display/display.h"
#include "rapid/pr2/pr2.h"
#include "rapid/sound/sound.h"
#include "ros/ros.h"
#include "std_msgs/Bool.h"

using code_it_pr2::RobotApi;
using rapid::display::MockDisplay;
using rapid::pr2::Pr2;
using rapid::sound::MockSound;
using rapid::sound::SoundPlay;
using ::testing::Return;

class RobotApiNodeTest : public ::testing::Test {
 public:
  RobotApiNodeTest()
      : nh_(),
        display_(),
        sound_(),
        pr2_(display_, sound_),
        api_(pr2_),
        say_srv_(
            nh_.advertiseService("code_it/api/say", &RobotApi::Say, &api_)),
        ask_mc_srv_(nh_.advertiseService("code_it/api/ask_multiple_choice",
                                         &RobotApi::AskMultipleChoice, &api_)),
        disp_msg_srv_(nh_.advertiseService("code_it/api/display_message",
                                           &RobotApi::DisplayMessage, &api_)),
        is_running_pub_(
            nh_.advertise<std_msgs::Bool>("code_it/is_program_running", 5)),
        is_running_sub_(
            nh_.subscribe("code_it/is_program_running", 10,
                          &RobotApiNodeTest::HandleProgramRunningMsg, this)),
        run_msg_received_(false) {}

  void SetUp() {
    while (!IsNodeReady()) {
      ros::spinOnce();
    }
  }

 protected:
  bool IsNodeReady() {
    return is_running_pub_.getNumSubscribers() > 0 &&
           is_running_sub_.getNumPublishers() > 0;
  }

  bool WaitForMessage(int timeout) {
    std_msgs::BoolConstPtr msg = ros::topic::waitForMessage<std_msgs::Bool>(
        is_running_sub_.getTopic(), nh_, ros::Duration(timeout));
    if (msg.get() == NULL) {
      return false;
    } else {
      return true;
    }
  }

  void HandleProgramRunningMsg(const std_msgs::Bool& msg) {
    api_.HandleProgramStopped(msg);
    run_msg_received_ = true;
  }

  ros::NodeHandle nh_;
  MockDisplay display_;
  MockSound sound_;
  Pr2 pr2_;
  RobotApi api_;
  ros::ServiceServer say_srv_;
  ros::ServiceServer ask_mc_srv_;
  ros::ServiceServer disp_msg_srv_;
  ros::Publisher is_running_pub_;
  ros::Subscriber is_running_sub_;

  bool run_msg_received_;
};

TEST_F(RobotApiNodeTest, TestCallsAreWiredUp) {
  EXPECT_CALL(sound_, Say("Hello world!"));
  bool on_time =
      ros::service::waitForService("code_it/api/say", ros::Duration(5));
  ASSERT_EQ(true, on_time);

  code_it::SayRequest req;
  req.text = "Hello world!";
  code_it::SayResponse res;
  bool success = ros::service::call("/code_it/api/say", req, res);
  EXPECT_EQ(true, success);
}

TEST_F(RobotApiNodeTest, TestScreenResetsOnProgramEnd) {
  EXPECT_CALL(display_, ShowDefault()).WillOnce(Return(true));
  std_msgs::Bool msg;
  msg.data = false;
  is_running_pub_.publish(msg);
  while (!run_msg_received_) {
    ros::spinOnce();
  }
}

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  ros::init(argc, argv, "robot_api_test");
  ros::AsyncSpinner spinner(1);
  spinner.start();
  int ret = RUN_ALL_TESTS();
  spinner.stop();
  ros::shutdown();
  return ret;
}
<|endoftext|>


<commit_before>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 2.1.1
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include "catch.hpp"

#include "json.hpp"
using nlohmann::json;

TEST_CASE("version information")
{
    SECTION("version()")
    {
        CHECK(json::meta()["name"] == "JSON for Modern C++");
        CHECK(json::meta()["version"] == json(
        {
            {"string", "2.1.1"},
            {"major", 2},
            {"minor", 1},
            {"patch", 1}
        }));
    }
}
<commit_msg>:white_check_mark: more tests for meta() call<commit_after>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 2.1.1
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.

Permission is hereby  granted, free of charge, to any  person obtaining a copy
of this software and associated  documentation files (the "Software"), to deal
in the Software  without restriction, including without  limitation the rights
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include "catch.hpp"

#include "json.hpp"
using nlohmann::json;

TEST_CASE("version information")
{
    SECTION("meta()")
    {
        json j = json::meta();

        CHECK(j["name"] == "JSON for Modern C++");
        CHECK(j["copyright"] == "(C) 2013-2017 Niels Lohmann");
        CHECK(j["url"] == "https://github.com/nlohmann/json");
        CHECK(j["version"] == json(
        {
            {"string", "2.1.1"},
            {"major", 2},
            {"minor", 1},
            {"patch", 1}
        }));
    }
}
<|endoftext|>