<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textprimitive2d.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hdu $ $Date: 2007-02-14 14:41:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE_TEXTPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_TEXTLAYOUTDEVICE_HXX
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
#endif

#ifndef _SV_VIRDEV_HXX
#include <vcl/virdev.hxx>
#endif

#ifndef _BGFX_COLOR_BCOLOR_HXX
#include <basegfx/color/bcolor.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_POLYPOLYGONPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
#include <basegfx/polygon/b2dpolygontools.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
#include <basegfx/polygon/b2dpolygon.hxx>
#endif

#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif

#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Font getVclFontFromFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform)
        {
            // decompose matrix to have position and size of text
            basegfx::B2DVector aScale, aTranslate;
            double fRotate, fShearX;
            rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
            return getVclFontFromFontAttributes(rFontAttributes, aScale, fRotate);
        }

        Font getVclFontFromFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DVector& rFontSize, double fFontRotation)
        {
            sal_uInt32 nWidth(basegfx::fround(fabs(rFontSize.getX())));
            sal_uInt32 nHeight(basegfx::fround(fabs(rFontSize.getY())));

            if(nWidth == nHeight)
            {
                nWidth = 0L;
            }

            Font aRetval(
                rFontAttributes.maFamilyName,
                rFontAttributes.maStyleName,
                Size(nWidth, nHeight));

            if(!basegfx::fTools::equalZero(fFontRotation))
            {
                sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
                aRetval.SetOrientation(aRotate10th % 3600);
            }

            aRetval.SetAlign(ALIGN_BASELINE);
            aRetval.SetCharSet(rFontAttributes.mbSymbol ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
            aRetval.SetVertical(rFontAttributes.mbVertical ? TRUE : FALSE);
            aRetval.SetWeight(static_cast<FontWeight>(rFontAttributes.mnWeight));
            aRetval.SetItalic(rFontAttributes.mbItalic ? ITALIC_NORMAL : ITALIC_NONE);

            return aRetval;
        }

        FontAttributes getFontAttributesFromVclFont(basegfx::B2DVector& rSize, const Font& rFont)
        {
            FontAttributes aRetval;

            aRetval.maFamilyName = rFont.GetName();
            aRetval.maStyleName = rFont.GetStyleName();
            aRetval.mbSymbol = (RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet());
            aRetval.mbVertical = rFont.IsVertical();
            aRetval.mnWeight = static_cast<sal_uInt16>(rFont.GetWeight());
            aRetval.mbItalic = (rFont.GetItalic() != ITALIC_NONE);

            const sal_Int32 nWidth(rFont.GetSize().getWidth());
            const sal_Int32 nHeight(rFont.GetSize().getHeight());
            rSize.setX(nWidth ? nWidth : nHeight);
            rSize.setY(nHeight);

            return aRetval;
        }
    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

using namespace com::sun::star;

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence TextSimplePortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            // get integer DXArray for getTextOutlines call (ATM uses vcl)
            ::std::vector< sal_Int32 > aNewIntegerDXArray;
            getIntegerDXArray(aNewIntegerDXArray);

            // prepare transformation matrices
            basegfx::B2DVector aScale, aTranslate;
            double fRotate, fShearX;
            getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX);
            basegfx::B2DHomMatrix aUnscaledTransform;
            aUnscaledTransform.rotate( fRotate );
            aUnscaledTransform.shearX( fShearX );
            aUnscaledTransform.translate( aTranslate.getX(), aTranslate.getY() );
            basegfx::B2DHomMatrix aUnrotatedTransform = getTextTransform();
            aUnrotatedTransform.rotate( -fRotate );

            // prepare textlayoutdevice
            TextLayouterDevice aTextLayouter;
            aTextLayouter.setFontAttributes(getFontAttributes(), aUnrotatedTransform );

            // get the text outlines
            basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
            aTextLayouter.getTextOutlines( aB2DPolyPolyVector,
                getText(), 0L, getText().Len(), aNewIntegerDXArray);

            // create primitives for the outlines
            const sal_uInt32 nCount = aB2DPolyPolyVector.size();
            if( nCount )
            {
                // prepare retval
                Primitive2DSequence aRetval(nCount);

                for(sal_uInt32 a(0L); a < nCount; a++)
                {
                    // prepare polygon
                    basegfx::B2DPolyPolygon& rPolyPolygon = aB2DPolyPolyVector[a];
                    rPolyPolygon.transform(aUnscaledTransform);

                    // create primitive
                    const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(rPolyPolygon, getFontColor()));
                    aRetval[a] = xRef;
                }

                return aRetval;
            }
            else
            {
                return Primitive2DSequence();
            }
        }

        TextSimplePortionPrimitive2D::TextSimplePortionPrimitive2D(
            const basegfx::B2DHomMatrix& rNewTransform,
            const String& rText,
            const ::std::vector< double >& rDXArray,
            const FontAttributes& rFontAttributes,
            const basegfx::BColor& rFontColor)
        :   BasePrimitive2D(),
            maTextTransform(rNewTransform),
            maText(rText),
            maDXArray(rDXArray),
            maFontAttributes(rFontAttributes),
            maFontColor(rFontColor)
        {
        }

        void TextSimplePortionPrimitive2D::getIntegerDXArray(::std::vector< sal_Int32 >& rDXArray) const
        {
            rDXArray.clear();

            if(getDXArray().size())
            {
                rDXArray.reserve(getDXArray().size());
                const basegfx::B2DVector aPixelVector(getTextTransform() * basegfx::B2DVector(1.0, 0.0));
                const double fPixelVectorLength(aPixelVector.getLength());

                for(::std::vector< double >::const_iterator aStart(getDXArray().begin()); aStart != getDXArray().end(); aStart++)
                {
                    rDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorLength));
                }
            }
        }

        bool TextSimplePortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
        {
            if(BasePrimitive2D::operator==(rPrimitive))
            {
                const TextSimplePortionPrimitive2D& rCompare = (TextSimplePortionPrimitive2D&)rPrimitive;

                return (getTextTransform() == rCompare.getTextTransform()
                    && getText() == rCompare.getText()
                    && getDXArray() == rCompare.getDXArray()
                    && getFontAttributes() == rCompare.getFontAttributes()
                    && getFontColor() == rCompare.getFontColor());
            }

            return false;
        }

        basegfx::B2DRange TextSimplePortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            const xub_StrLen aStrLen(getText().Len());
            basegfx::B2DRange aRetval;

            if(aStrLen)
            {
                // get TextBoundRect as base size
                TextLayouterDevice aTextLayouter;
                aTextLayouter.setFontAttributes(getFontAttributes(), getTextTransform());
                aRetval = aTextLayouter.getTextBoundRect(getText(), 0L, aStrLen);

                // apply textTransform to it, but without scaling. The scale defines the font size
                // which is already part of the fetched textRange
                basegfx::B2DVector aScale, aTranslate;
                double fRotate, fShearX;
                basegfx::B2DHomMatrix aTextTransformWithoutScale;

                getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX);
                aTextTransformWithoutScale.shearX(fShearX);
                aTextTransformWithoutScale.rotate(fRotate);
                aTextTransformWithoutScale.translate(aTranslate.getX(), aTranslate.getY());
                aRetval.transform(aTextTransformWithoutScale);
            }

            return aRetval;
        }

        // provide unique ID
        ImplPrimitrive2DIDBlock(TextSimplePortionPrimitive2D, '2','T','S','i')

    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence TextComplexPortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            // TODO: need to take care of
            // -underline
            // -strikethrough
            // -emphasis mark
            // -relief (embosses/engraved)
            // -shadow
            // -outline

            // ATM: Just create a simple text primitive and ignore other attributes
            const Primitive2DReference xRef(new TextSimplePortionPrimitive2D(getTextTransform(), getText(), getDXArray(), getFontAttributes(), getFontColor()));
            return Primitive2DSequence(&xRef, 1L);
        }

        TextComplexPortionPrimitive2D::TextComplexPortionPrimitive2D(
            const basegfx::B2DHomMatrix& rNewTransform,
            const String& rText,
            const ::std::vector< double >& rDXArray,
            const FontAttributes& rFontAttributes,
            const basegfx::BColor& rFontColor,
            FontUnderline eFontUnderline,
            bool bUnderlineAbove,
            FontStrikeout eFontStrikeout,
            bool bWordLineMode,
            FontEmphasisMark eFontEmphasisMark,
            bool bEmphasisMarkAbove,
            bool bEmphasisMarkBelow,
            FontRelief eFontRelief,
            bool bShadow,
            bool bOutline)
        :   TextSimplePortionPrimitive2D(rNewTransform, rText, rDXArray, rFontAttributes, rFontColor),
            meFontUnderline(eFontUnderline),
            meFontStrikeout(eFontStrikeout),
            meFontEmphasisMark(eFontEmphasisMark),
            meFontRelief(eFontRelief),
            mbUnderlineAbove(bUnderlineAbove),
            mbWordLineMode(bWordLineMode),
            mbEmphasisMarkAbove(bEmphasisMarkAbove),
            mbEmphasisMarkBelow(bEmphasisMarkBelow),
            mbShadow(bShadow),
            mbOutline(bOutline)
        {
        }

        bool TextComplexPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
        {
            if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
            {
                const TextComplexPortionPrimitive2D& rCompare = (TextComplexPortionPrimitive2D&)rPrimitive;

                return (getFontUnderline() == rCompare.getFontUnderline()
                    && getFontStrikeout() == rCompare.getFontStrikeout()
                    && getUnderlineAbove() == rCompare.getUnderlineAbove()
                    && getWordLineMode() == rCompare.getWordLineMode()
                    && getFontEmphasisMark() == rCompare.getFontEmphasisMark()
                    && getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
                    && getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
                    && getFontRelief() == rCompare.getFontRelief()
                    && getShadow() == rCompare.getShadow()
                    && getOutline() == rCompare.getOutline());
            }

            return false;
        }

        // provide unique ID
        ImplPrimitrive2DIDBlock(TextComplexPortionPrimitive2D, '2','T','C','o')

    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////
// eof
<commit_msg>#i73860# implement outline font attribute<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textprimitive2d.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hdu $ $Date: 2007-02-15 13:25:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE_TEXTPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_TEXTLAYOUTDEVICE_HXX
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
#endif

#ifndef _SV_VIRDEV_HXX
#include <vcl/virdev.hxx>
#endif

#ifndef _BGFX_COLOR_BCOLOR_HXX
#include <basegfx/color/bcolor.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_POLYPOLYGONPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_POLYGONPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#endif

#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_STROKEATTRIBUTE_HXX
#include <drawinglayer/attribute/strokeattribute.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
#include <basegfx/polygon/b2dpolygontools.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
#include <basegfx/polygon/b2dpolygon.hxx>
#endif

#ifndef _BGFX_POLYGON_B2DLINEGEOMETRY_HXX
#include <basegfx/polygon/b2dlinegeometry.hxx>
#endif

#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif

#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
#include <basegfx/tools/canvastools.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Font getVclFontFromFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DHomMatrix& rTransform)
        {
            // decompose matrix to have position and size of text
            basegfx::B2DVector aScale, aTranslate;
            double fRotate, fShearX;
            rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
            return getVclFontFromFontAttributes(rFontAttributes, aScale, fRotate);
        }

        Font getVclFontFromFontAttributes(const FontAttributes& rFontAttributes, const basegfx::B2DVector& rFontSize, double fFontRotation)
        {
            sal_uInt32 nWidth(basegfx::fround(fabs(rFontSize.getX())));
            sal_uInt32 nHeight(basegfx::fround(fabs(rFontSize.getY())));

            if(nWidth == nHeight)
            {
                nWidth = 0L;
            }

            Font aRetval(
                rFontAttributes.maFamilyName,
                rFontAttributes.maStyleName,
                Size(nWidth, nHeight));

            if(!basegfx::fTools::equalZero(fFontRotation))
            {
                sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI)));
                aRetval.SetOrientation(aRotate10th % 3600);
            }

            aRetval.SetAlign(ALIGN_BASELINE);
            aRetval.SetCharSet(rFontAttributes.mbSymbol ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
            aRetval.SetVertical(rFontAttributes.mbVertical ? TRUE : FALSE);
            aRetval.SetWeight(static_cast<FontWeight>(rFontAttributes.mnWeight));
            aRetval.SetItalic(rFontAttributes.mbItalic ? ITALIC_NORMAL : ITALIC_NONE);
            aRetval.SetOutline(rFontAttributes.mbOutline);

            return aRetval;
        }

        FontAttributes getFontAttributesFromVclFont(basegfx::B2DVector& rSize, const Font& rFont)
        {
            FontAttributes aRetval;

            aRetval.maFamilyName = rFont.GetName();
            aRetval.maStyleName = rFont.GetStyleName();
            aRetval.mbSymbol = (RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet());
            aRetval.mbVertical = rFont.IsVertical();
            aRetval.mnWeight = static_cast<sal_uInt16>(rFont.GetWeight());
            aRetval.mbItalic = (rFont.GetItalic() != ITALIC_NONE);
            aRetval.mbOutline = rFont.IsOutline();
            // TODO: eKerning

            const sal_Int32 nWidth(rFont.GetSize().getWidth());
            const sal_Int32 nHeight(rFont.GetSize().getHeight());
            rSize.setX(nWidth ? nWidth : nHeight);
            rSize.setY(nHeight);

            return aRetval;
        }
    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

using namespace com::sun::star;

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence TextSimplePortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            // get integer DXArray for getTextOutlines call (ATM uses vcl)
            ::std::vector< sal_Int32 > aNewIntegerDXArray;
            getIntegerDXArray(aNewIntegerDXArray);

            // prepare transformation matrices
            basegfx::B2DVector aScale, aTranslate;
            double fRotate, fShearX;
            getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX);
            basegfx::B2DHomMatrix aUnscaledTransform;
            aUnscaledTransform.rotate( fRotate );
            aUnscaledTransform.shearX( fShearX );
            aUnscaledTransform.translate( aTranslate.getX(), aTranslate.getY() );
            basegfx::B2DHomMatrix aUnrotatedTransform = getTextTransform();
            aUnrotatedTransform.rotate( -fRotate );

            // prepare textlayoutdevice
            TextLayouterDevice aTextLayouter;
            aTextLayouter.setFontAttributes(getFontAttributes(), aUnrotatedTransform );

            // get the text outlines
            basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
            aTextLayouter.getTextOutlines( aB2DPolyPolyVector,
                getText(), 0L, getText().Len(), aNewIntegerDXArray);

            // create primitives for the outlines
            const sal_uInt32 nCount = aB2DPolyPolyVector.size();
            Primitive2DSequence aRetval;

            if( !nCount )
            {
                // for invisible glyphs
                return aRetval;
            }
            else if( !getFontAttributes().mbOutline )
            {
                aRetval.realloc(nCount);
                // for the glyph shapes as color-filled polypolygons
                for(sal_uInt32 a(0L); a < nCount; a++)
                {
                    // prepare polypolygon
                    basegfx::B2DPolyPolygon& rPolyPolygon = aB2DPolyPolyVector[a];
                    rPolyPolygon.transform(aUnscaledTransform);

                    const Primitive2DReference xRef(new PolyPolygonColorPrimitive2D(rPolyPolygon, getFontColor()));
                    aRetval[a] = xRef;
                }
            }
            else
            {
                // for the glyph outlines as stroked polygons
                // since there is no primitive for stroked polypolygons
                int nPolyCount = 0;
                for(sal_uInt32 a(0L); a < nCount; a++)
                    nPolyCount += aB2DPolyPolyVector[a].count();
                aRetval.realloc(nPolyCount);

                double fStrokeWidth = 1.0 + aScale.getY() * 0.02;
                if( getFontAttributes().mnWeight > WEIGHT_SEMIBOLD )
                    fStrokeWidth *= 1.4;
                else if( getFontAttributes().mnWeight < WEIGHT_SEMILIGHT )
                    fStrokeWidth *= 0.7;
                const drawinglayer::attribute::StrokeAttribute aStrokeAttr( getFontColor(),
                    fStrokeWidth, basegfx::tools::B2DLINEJOIN_NONE );
                for(sal_uInt32 a(0L), b(0L); a < nCount; a++)
                {
                    basegfx::B2DPolyPolygon& rPolyPolygon = aB2DPolyPolyVector[a];
                    rPolyPolygon.transform(aUnscaledTransform);
                    for( unsigned i(0L); i < rPolyPolygon.count(); ++i )
                    {
                        const basegfx::B2DPolygon& rPolygon = rPolyPolygon.getB2DPolygon(i);
                        const Primitive2DReference xRef(new PolygonStrokePrimitive2D(rPolygon, aStrokeAttr));
                        aRetval[b++] = xRef;
                    }
                }
            }

            return aRetval;
        }

        TextSimplePortionPrimitive2D::TextSimplePortionPrimitive2D(
            const basegfx::B2DHomMatrix& rNewTransform,
            const String& rText,
            const ::std::vector< double >& rDXArray,
            const FontAttributes& rFontAttributes,
            const basegfx::BColor& rFontColor)
        :   BasePrimitive2D(),
            maTextTransform(rNewTransform),
            maText(rText),
            maDXArray(rDXArray),
            maFontAttributes(rFontAttributes),
            maFontColor(rFontColor)
        {
        }

        void TextSimplePortionPrimitive2D::getIntegerDXArray(::std::vector< sal_Int32 >& rDXArray) const
        {
            rDXArray.clear();

            if(getDXArray().size())
            {
                rDXArray.reserve(getDXArray().size());
                const basegfx::B2DVector aPixelVector(getTextTransform() * basegfx::B2DVector(1.0, 0.0));
                const double fPixelVectorLength(aPixelVector.getLength());

                for(::std::vector< double >::const_iterator aStart(getDXArray().begin()); aStart != getDXArray().end(); aStart++)
                {
                    rDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorLength));
                }
            }
        }

        bool TextSimplePortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
        {
            if(BasePrimitive2D::operator==(rPrimitive))
            {
                const TextSimplePortionPrimitive2D& rCompare = (TextSimplePortionPrimitive2D&)rPrimitive;

                return (getTextTransform() == rCompare.getTextTransform()
                    && getText() == rCompare.getText()
                    && getDXArray() == rCompare.getDXArray()
                    && getFontAttributes() == rCompare.getFontAttributes()
                    && getFontColor() == rCompare.getFontColor());
            }

            return false;
        }

        basegfx::B2DRange TextSimplePortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            const xub_StrLen aStrLen(getText().Len());
            basegfx::B2DRange aRetval;

            if(aStrLen)
            {
                // get TextBoundRect as base size
                TextLayouterDevice aTextLayouter;
                aTextLayouter.setFontAttributes(getFontAttributes(), getTextTransform());
                aRetval = aTextLayouter.getTextBoundRect(getText(), 0L, aStrLen);

                // apply textTransform to it, but without scaling. The scale defines the font size
                // which is already part of the fetched textRange
                basegfx::B2DVector aScale, aTranslate;
                double fRotate, fShearX;
                basegfx::B2DHomMatrix aTextTransformWithoutScale;

                getTextTransform().decompose(aScale, aTranslate, fRotate, fShearX);
                aTextTransformWithoutScale.shearX(fShearX);
                aTextTransformWithoutScale.rotate(fRotate);
                aTextTransformWithoutScale.translate(aTranslate.getX(), aTranslate.getY());
                aRetval.transform(aTextTransformWithoutScale);
            }

            return aRetval;
        }

        // provide unique ID
        ImplPrimitrive2DIDBlock(TextSimplePortionPrimitive2D, '2','T','S','i')

    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence TextComplexPortionPrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
        {
            Primitive2DSequence aRetval(1);

            // First create a simple text primitive and ignore other attributes
            aRetval[0] = new TextSimplePortionPrimitive2D(getTextTransform(), getText(), getDXArray(), getFontAttributes(), getFontColor());

                // TODO: need to take care of
                // -underline
                // -strikethrough
                // -emphasis mark
                // -relief (embosses/engraved)
                // -shadow
                // -outline

            return aRetval;
        }

        TextComplexPortionPrimitive2D::TextComplexPortionPrimitive2D(
            const basegfx::B2DHomMatrix& rNewTransform,
            const String& rText,
            const ::std::vector< double >& rDXArray,
            const FontAttributes& rFontAttributes,
            const basegfx::BColor& rFontColor,
            FontUnderline eFontUnderline,
            bool bUnderlineAbove,
            FontStrikeout eFontStrikeout,
            bool bWordLineMode,
            FontEmphasisMark eFontEmphasisMark,
            bool bEmphasisMarkAbove,
            bool bEmphasisMarkBelow,
            FontRelief eFontRelief,
            bool bShadow,
            bool bOutline)
        :   TextSimplePortionPrimitive2D(rNewTransform, rText, rDXArray, rFontAttributes, rFontColor),
            meFontUnderline(eFontUnderline),
            meFontStrikeout(eFontStrikeout),
            meFontEmphasisMark(eFontEmphasisMark),
            meFontRelief(eFontRelief),
            mbUnderlineAbove(bUnderlineAbove),
            mbWordLineMode(bWordLineMode),
            mbEmphasisMarkAbove(bEmphasisMarkAbove),
            mbEmphasisMarkBelow(bEmphasisMarkBelow),
            mbShadow(bShadow),
            mbOutline(bOutline)
        {
        }

        bool TextComplexPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
        {
            if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
            {
                const TextComplexPortionPrimitive2D& rCompare = (TextComplexPortionPrimitive2D&)rPrimitive;

                return (getFontUnderline() == rCompare.getFontUnderline()
                    && getFontStrikeout() == rCompare.getFontStrikeout()
                    && getUnderlineAbove() == rCompare.getUnderlineAbove()
                    && getWordLineMode() == rCompare.getWordLineMode()
                    && getFontEmphasisMark() == rCompare.getFontEmphasisMark()
                    && getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
                    && getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
                    && getFontRelief() == rCompare.getFontRelief()
                    && getShadow() == rCompare.getShadow()
                    && getOutline() == rCompare.getOutline());
            }

            return false;
        }

        // provide unique ID
        ImplPrimitrive2DIDBlock(TextComplexPortionPrimitive2D, '2','T','C','o')

    } // end of namespace primitive2d
} // end of namespace drawinglayer

//////////////////////////////////////////////////////////////////////////////
// eof
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2022, Eyal Rozenberg, under the terms of the 3-clause
 * BSD software license; see the LICENSE file accompanying this
 * repository.
 *
 * Copyright notice and license for the original code:
 * Copyright (c) 1993-2015, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cuda_runtime.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

// Convenience function for checking CUDA runtime API results
// can be wrapped around any runtime API call. No-op in release builds.
inline
cudaError_t checkCuda(cudaError_t result)
{
#if defined(DEBUG) || defined(_DEBUG)
	if (result != cudaSuccess) {
    fprintf(stderr, "CUDA Runtime Error: %s\n", cudaGetErrorString(result));
    assert(result == cudaSuccess);
  }
#endif
	return result;
}

void profileCopies(float        *h_a,
				   float        *h_b,
				   float        *d,
				   size_t       nElements,
				   char const   *desc)
{
	printf("\n%s transfers\n", desc);

	size_t bytes = nElements * sizeof(float);

	// events for timing
	cudaEvent_t startEvent, stopEvent;

	checkCuda( cudaEventCreate(&startEvent) );
	checkCuda( cudaEventCreate(&stopEvent) );

	checkCuda( cudaEventRecord(startEvent, 0) );
	checkCuda( cudaMemcpy(d, h_a, bytes, cudaMemcpyHostToDevice) );
	checkCuda( cudaEventRecord(stopEvent, 0) );
	checkCuda( cudaEventSynchronize(stopEvent) );

	float time;
	checkCuda( cudaEventElapsedTime(&time, startEvent, stopEvent) );
	printf("  Host to Device bandwidth (GB/s): %f\n", bytes * 1e-6 / time);

	checkCuda( cudaEventRecord(startEvent, 0) );
	checkCuda( cudaMemcpy(h_b, d, bytes, cudaMemcpyDeviceToHost) );
	checkCuda( cudaEventRecord(stopEvent, 0) );
	checkCuda( cudaEventSynchronize(stopEvent) );

	checkCuda( cudaEventElapsedTime(&time, startEvent, stopEvent) );
	printf("  Device to Host bandwidth (GB/s): %f\n", bytes * 1e-6 / time);

	for (size_t i = 0; i < nElements; ++i) {
		if (h_a[i] != h_b[i]) {
			printf("*** %s transfers failed ***", desc);
			break;
		}
	}

	// clean up events
	checkCuda( cudaEventDestroy(startEvent) );
	checkCuda( cudaEventDestroy(stopEvent) );
}

int main()
{
	const size_t nElements = 4*1024*1024;
	const size_t bytes = nElements * sizeof(float);

	// host arrays
	float *h_aPageable, *h_bPageable;
	float *h_aPinned, *h_bPinned;

	// device array
	float *d_a;

	// allocate and initialize
	h_aPageable = (float*)malloc(bytes);                    // host pageable
	h_bPageable = (float*)malloc(bytes);                    // host pageable
	checkCuda( cudaMallocHost((void**)&h_aPinned, bytes) ); // host pinned
	checkCuda( cudaMallocHost((void**)&h_bPinned, bytes) ); // host pinned
	checkCuda( cudaMalloc((void**)&d_a, bytes) );           // device

	for (size_t i = 0; i < nElements; ++i) h_aPageable[i] = i;
	memcpy(h_aPinned, h_aPageable, bytes);
	memset(h_bPageable, 0, bytes);
	memset(h_bPinned, 0, bytes);

	// output device info and transfer size
	cudaDeviceProp prop;
	checkCuda( cudaGetDeviceProperties(&prop, 0) );

	printf("\nDevice: %s\n", prop.name);
	printf("Transfer size (MB): %zu\n", bytes / (size_t) (1024 * 1024));

	// perform copies and report bandwidth
	profileCopies(h_aPageable, h_bPageable, d_a, nElements, "Pageable");
	profileCopies(h_aPinned, h_bPinned, d_a, nElements, "Pinned");

	printf("\n");

	// cleanup
	cudaFree(d_a);
	cudaFreeHost(h_aPinned);
	cudaFreeHost(h_bPinned);
	free(h_aPageable);
	free(h_bPageable);

	return 0;
}
<commit_msg>Fixes #398: Adapted the bandwidthtest program to use our wrappers.<commit_after>/*
 * Copyright (c) 2022, Eyal Rozenberg, under the terms of the 3-clause
 * BSD software license; see the LICENSE file accompanying this
 * repository.
 *
 * Copyright notice and license for the original code:
 * Copyright (c) 1993-2015, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cuda/api.hpp>

#include <memory>
#include <array>
#include <utility>
#include <algorithm>
#include <numeric>

void profileCopies(float        *h_a,
				   float        *h_b,
				   float        *d,
				   size_t       nElements,
				   char const   *desc)
{
	std::cout << desc << " transfers\n";

	size_t bytes = nElements * sizeof(float);

	auto device = cuda::device::current::get();
	auto stream = device.default_stream();
	auto events = std::make_pair(device.create_event(), device.create_event());
	stream.enqueue.event(events.first);
	stream.enqueue.copy(d, h_a, bytes);
	stream.enqueue.event(events.second);
	stream.synchronize();

	auto duration = cuda::event::time_elapsed_between(events.first, events.second);
	std::cout << "  Host to Device bandwidth (GB/s): " << (bytes * 1e-6 / duration.count()) << "\n";

	stream.enqueue.event(events.first);
	stream.enqueue.copy(h_b, d, bytes);
	stream.enqueue.event(events.second);
	stream.synchronize();

	duration = cuda::event::time_elapsed_between(events.first, events.second);
	std::cout << "  Device to Host bandwidth (GB/s): " << (bytes * 1e-6 / duration.count()) << "\n";

	bool are_equal = std::equal(h_a, h_a + nElements, h_b);
	if (not are_equal) {
		std::cout << "*** " << desc << " transfers failed ***\n";
	}
}

int main()
{
	constexpr const size_t Mi = 1024 * 1024;
	const size_t nElements = 4 * Mi;
	const size_t bytes = nElements * sizeof(float);

	auto pageable_host_buffers = std::make_pair(
		std::unique_ptr<float[]>(new float[nElements]),
		std::unique_ptr<float[]>(new float[nElements])
	);

	auto device_buffer = cuda::memory::device::make_unique<float[]>(nElements);

	auto pinned_host_buffers = std::make_pair(
		cuda::memory::host::make_unique<float[]>(nElements),
		cuda::memory::host::make_unique<float[]>(nElements)
	);

	auto h_aPageable = pageable_host_buffers.first.get();
	auto h_bPageable = pageable_host_buffers.second.get();
	auto h_aPinned = pinned_host_buffers.first.get();
	auto h_bPinned = pinned_host_buffers.second.get();

	std::iota(h_aPageable, h_aPageable + nElements, 0);
	cuda::memory::copy(h_aPinned, h_aPageable, bytes);
	// Note: the following two instructions can be replaced with CUDA API wrappers
	// calls - cuda::memory::host::zero(), but that won't improve anything
	std::fill_n(h_bPageable, nElements, (float) 0);
	std::fill_n(h_bPinned, nElements, (float) 0);

	std::cout << "\nDevice: " << cuda::device::current::get().name() << "\n";
	std::cout << "\nTransfer size (MB): " << (bytes / Mi) << "\n";

	// perform copies and report bandwidth
	profileCopies(h_aPageable, h_bPageable, device_buffer.get(), nElements, "Pageable");
	profileCopies(h_aPinned, h_bPinned, device_buffer.get(), nElements, "Pinned");
}
<|endoftext|>


<commit_before>/*____________________________________________________________________________

  MusicBrainz -- The Internet music metadatabase

  Portions Copyright (C) 2000 Relatable

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   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

  $Id$
____________________________________________________________________________*/

//------------------------------------
//  fft.cpp
//  The implementation of the
//  Fast Fourier Transform algorithm
//  modified by Sean Ward 2000
//  portions (c) Reliable Software, 1996
//------------------------------------
#include "sigfft.h"
#include <string.h>

// log (1) = 0, log(2) = 1, log(3) = 2, log(4) = 2 ...

#define PI (2.0 * asin(1.0))

// Points must be a power of 2

FFT::FFT (int Points, long sampleRate)
: _Points (Points), _sampleRate (sampleRate)
{
    _aTape = new double [_Points];
#if 0
    // 1 kHz calibration wave
    for (int i = 0; i < _Points; i++)
        _aTape[i] = 1600 * sin (2 * PI * 1000. * i / _sampleRate);
#else
    int i = 0;
    for (i = 0; i < _Points; i++)
        _aTape[i] = 0;
#endif
    _sqrtPoints = sqrt((double)_Points);
    // calculate binary log
    _logPoints = 0;
    Points--;
    while (Points != 0)
    {
        Points >>= 1;
        _logPoints++;
    }

    _aBitRev = new int [_Points];
    _test = new Complex[_Points];
    _W = new Complex* [_logPoints+1];
    // Precompute complex exponentials
    int _2_l = 2;
    for (int l = 1; l <= _logPoints; l++)
    {
        _W[l] = new Complex [_Points];

        for ( int i = 0; i < _Points; i++ )
        {
            double re =  cos (2. * PI * i / _2_l);
            double im = -sin (2. * PI * i / _2_l);
            _W[l][i] = Complex (re, im);
        }
        _2_l *= 2;
    }

    // set up bit reverse mapping
    int rev = 0;
    int halfPoints = _Points/2;
    for (i = 0; i < _Points - 1; i++)
    {
        _aBitRev[i] = rev;
        int mask = halfPoints;
        // add 1 backwards
        while (rev >= mask)
        {
            rev -= mask; // turn off this bit
            mask >>= 1;
        }
        rev += mask;
    }
    _aBitRev [_Points-1] = _Points-1;
}

FFT::~FFT()
{
    delete []_aTape;
    delete []_aBitRev;
    for (int l = 1; l <= _logPoints; l++)
    {
        delete []_W[l];
    }
    delete []_W;
    delete []_test;
}

//void Fft::CopyIn (SampleIter& iter)
void FFT::CopyIn(char* pBuffer, int nNumSamples)
{
    if (nNumSamples > _Points)
        return;

    // make space for cSample samples at the end of tape
    // shifting previous samples towards the beginning
    memmove (_aTape, &_aTape[nNumSamples],
              (_Points - nNumSamples) * sizeof(double));
    // copy samples from iterator to tail end of tape
    int iTail  = _Points - nNumSamples;
    int i = 0;
    for (i = 0; i < nNumSamples; i++)
    {
        _aTape [i + iTail] = (double) pBuffer[i];
    }
    // Initialize the FFT buffer
    for (i = 0; i < _Points; i++)
        PutAt (i, _aTape[i]);
}

//
//               0   1   2   3   4   5   6   7
//  level   1
//  step    1                                     0
//  increm  2                                   W
//  j = 0        <--->   <--->   <--->   <--->   1
//  level   2
//  step    2
//  increm  4                                     0
//  j = 0        <------->       <------->      W      1
//  j = 1            <------->       <------->   2   W
//  level   3                                         2
//  step    4
//  increm  8                                     0
//  j = 0        <--------------->              W      1
//  j = 1            <--------------->           3   W      2
//  j = 2                <--------------->            3   W      3
//  j = 3                    <--------------->             3   W
//                                                              3
//

void FFT::Transform ()
{
    // step = 2 ^ (level-1)
    // increm = 2 ^ level;
    int step = 1;
    for (int level = 1; level <= _logPoints; level++)
    {
        int increm = step * 2;
        for (int j = 0; j < step; j++)
        {
            // U = exp ( - 2 PI j / 2 ^ level )
            Complex U = _W [level][j];
            for (int i = j; i < _Points; i += increm)
            {
                // butterfly
                Complex T = U;
                T *= _test [i+step];
                _test [i+step] = _test [i];
                _test [i+step] -= T;
                _test [i] += T;
            }
        }
        step *= 2;
    }
}

<commit_msg>- testing the commits script<commit_after>/*____________________________________________________________________________

  MusicBrainz -- The Internet music metadatabase

  Portions Copyright (C) 2000 Relatable

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   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

  $Id$
____________________________________________________________________________*/

//------------------------------------
//  fft.cpp
//  The implementation of the
//  Fast Fourier Transform algorithm
//  modified by Sean Ward 2000
//  portions (c) Reliable Software, 1996
//------------------------------------
#include "sigfft.h"
#include <string.h>

//  log (1) = 0, log(2) = 1, log(3) = 2, log(4) = 2 ...

#define PI (2.0 * asin(1.0))

// Points must be a power of 2

FFT::FFT (int Points, long sampleRate)
: _Points (Points), _sampleRate (sampleRate)
{
    _aTape = new double [_Points];
#if 0
    // 1 kHz calibration wave
    for (int i = 0; i < _Points; i++)
        _aTape[i] = 1600 * sin (2 * PI * 1000. * i / _sampleRate);
#else
    int i = 0;
    for (i = 0; i < _Points; i++)
        _aTape[i] = 0;
#endif
    _sqrtPoints = sqrt((double)_Points);
    // calculate binary log
    _logPoints = 0;
    Points--;
    while (Points != 0)
    {
        Points >>= 1;
        _logPoints++;
    }

    _aBitRev = new int [_Points];
    _test = new Complex[_Points];
    _W = new Complex* [_logPoints+1];
    // Precompute complex exponentials
    int _2_l = 2;
    for (int l = 1; l <= _logPoints; l++)
    {
        _W[l] = new Complex [_Points];

        for ( int i = 0; i < _Points; i++ )
        {
            double re =  cos (2. * PI * i / _2_l);
            double im = -sin (2. * PI * i / _2_l);
            _W[l][i] = Complex (re, im);
        }
        _2_l *= 2;
    }

    // set up bit reverse mapping
    int rev = 0;
    int halfPoints = _Points/2;
    for (i = 0; i < _Points - 1; i++)
    {
        _aBitRev[i] = rev;
        int mask = halfPoints;
        // add 1 backwards
        while (rev >= mask)
        {
            rev -= mask; // turn off this bit
            mask >>= 1;
        }
        rev += mask;
    }
    _aBitRev [_Points-1] = _Points-1;
}

FFT::~FFT()
{
    delete []_aTape;
    delete []_aBitRev;
    for (int l = 1; l <= _logPoints; l++)
    {
        delete []_W[l];
    }
    delete []_W;
    delete []_test;
}

//void Fft::CopyIn (SampleIter& iter)
void FFT::CopyIn(char* pBuffer, int nNumSamples)
{
    if (nNumSamples > _Points)
        return;

    // make space for cSample samples at the end of tape
    // shifting previous samples towards the beginning
    memmove (_aTape, &_aTape[nNumSamples],
              (_Points - nNumSamples) * sizeof(double));
    // copy samples from iterator to tail end of tape
    int iTail  = _Points - nNumSamples;
    int i = 0;
    for (i = 0; i < nNumSamples; i++)
    {
        _aTape [i + iTail] = (double) pBuffer[i];
    }
    // Initialize the FFT buffer
    for (i = 0; i < _Points; i++)
        PutAt (i, _aTape[i]);
}

//
//               0   1   2   3   4   5   6   7
//  level   1
//  step    1                                     0
//  increm  2                                   W
//  j = 0        <--->   <--->   <--->   <--->   1
//  level   2
//  step    2
//  increm  4                                     0
//  j = 0        <------->       <------->      W      1
//  j = 1            <------->       <------->   2   W
//  level   3                                         2
//  step    4
//  increm  8                                     0
//  j = 0        <--------------->              W      1
//  j = 1            <--------------->           3   W      2
//  j = 2                <--------------->            3   W      3
//  j = 3                    <--------------->             3   W
//                                                              3
//

void FFT::Transform ()
{
    // step = 2 ^ (level-1)
    // increm = 2 ^ level;
    int step = 1;
    for (int level = 1; level <= _logPoints; level++)
    {
        int increm = step * 2;
        for (int j = 0; j < step; j++)
        {
            // U = exp ( - 2 PI j / 2 ^ level )
            Complex U = _W [level][j];
            for (int i = j; i < _Points; i += increm)
            {
                // butterfly
                Complex T = U;
                T *= _test [i+step];
                _test [i+step] = _test [i];
                _test [i+step] -= T;
                _test [i] += T;
            }
        }
        step *= 2;
    }
}

<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013, 2017-2018 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/*
 * Simulated Low Level Driver for the PX4 audio alarm port. Subscribes to
 * tune_control and plays notes on this architecture specific
 * timer HW
 */

#include <px4_config.h>
#include <px4_posix.h>

#include <drivers/device/device.h>
#include <drivers/drv_tone_alarm.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>

#include <board_config.h>
#include <drivers/drv_hrt.h>

#include <systemlib/err.h>
#include <circuit_breaker/circuit_breaker.h>

#include <lib/tunes/tunes.h>
#include <uORB/uORB.h>
#include <uORB/topics/tune_control.h>

#include "VirtDevObj.hpp"

using namespace DriverFramework;

#if !defined(UNUSED)
#  define UNUSED(a) ((void)(a))
#endif

#define CBRK_BUZZER_KEY 782097

class ToneAlarm : public VirtDevObj
{
public:
	ToneAlarm();
	~ToneAlarm();

	virtual int init();
	void status();

	enum {
		CBRK_OFF = 0,
		CBRK_ON,
		CBRK_UNINIT
	};

private:
	volatile bool _running;
	volatile bool _should_run;
	bool _play_tone;

	Tunes _tunes;

	hrt_call		_note_call;	// HRT callout for note completion

	unsigned _silence_length; // if nonzero, silence before next note

	int _cbrk; ///< if true, no audio output
	int _tune_control_sub;

	tune_control_s _tune;

	// Convert a frequency value into a divisor for the configured timer's clock.
	//
	unsigned frequency_to_divisor(unsigned frequency);

	// Start playing the note
	//
	void start_note(unsigned frequency);

	// Stop playing the current note and make the player 'safe'
	//
	void stop_note();

	// Parse the next note out of the string and play it
	//
	void next_note();

	// hrt_call trampoline for next_note
	//
	static void next_trampoline(void *arg);

	// Unused
	virtual void _measure() {}
};

/*
 * Driver 'main' command.
 */
extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]);

ToneAlarm::ToneAlarm() :
	VirtDevObj("tone_alarm", TONEALARM0_DEVICE_PATH, nullptr, 0),
	_running(false),
	_should_run(true),
	_play_tone(false),
	_tunes(),
	_silence_length(0),
	_cbrk(CBRK_UNINIT),
	_tune_control_sub(-1)
{
}

ToneAlarm::~ToneAlarm()
{
	_should_run = false;
	int counter = 0;

	while (_running && ++counter < 10) {
		usleep(100000);
	}
}

int ToneAlarm::init()
{
	int ret;

	ret = VirtDevObj::init();

	if (ret != OK) {
		return ret;
	}

	_note_call = {};
	hrt_call_after(&_note_call, (hrt_abstime)TUNE_MAX_UPDATE_INTERVAL_US, (hrt_callout)next_trampoline, this);
	_running = true;
	return OK;
}

void ToneAlarm::status()
{
	if (_running) {
		PX4_INFO("running");

	} else {
		PX4_INFO("stopped");
	}
}

unsigned ToneAlarm::frequency_to_divisor(unsigned frequency)
{
	const int TONE_ALARM_CLOCK = 120000000ul / 4;

	float period = 0.5f / frequency;

	// and the divisor, rounded to the nearest integer
	unsigned divisor = (period * TONE_ALARM_CLOCK) + 0.5f;

	return divisor;
}

void ToneAlarm::start_note(unsigned frequency)
{
	// check if circuit breaker is enabled
	if (_cbrk == CBRK_UNINIT) {
		_cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY);
	}

	if (_cbrk != CBRK_OFF) { return; }

	// compute the divisor
	unsigned divisor = frequency_to_divisor(frequency);

	// pick the lowest prescaler value that we can use
	// (note that the effective prescale value is 1 greater)
	unsigned prescale = divisor / 65536;

	// calculate the timer period for the selected prescaler value
	unsigned period = (divisor / (prescale + 1)) - 1;

	// Silence warning of unused var
	UNUSED(period);
	PX4_DEBUG("ToneAlarm::start_note %u", period);
}

void ToneAlarm::stop_note()
{
}

void ToneAlarm::next_note()
{
	if (!_should_run) {
		if (_tune_control_sub >= 0) {
			orb_unsubscribe(_tune_control_sub);
		}

		_running = false;
		return;
	}

	// subscribe to tune_control
	if (_tune_control_sub < 0) {
		_tune_control_sub = orb_subscribe(ORB_ID(tune_control));
	}

	// do we have an inter-note gap to wait for?
	if (_silence_length > 0) {
		stop_note();
		_note_call = {};
		hrt_call_after(&_note_call, (hrt_abstime)_silence_length, (hrt_callout)next_trampoline, this);
		_silence_length = 0;
		return;
	}

	// check for updates
	bool updated = false;
	orb_check(_tune_control_sub, &updated);

	if (updated) {
		orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune);
		_play_tone = _tunes.set_control(_tune) == 0;
	}

	unsigned frequency = 0;
	unsigned duration = 0;

	if (_play_tone) {
		_play_tone = false;
		int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length);

		if (parse_ret_val >= 0) {
			// a frequency of 0 correspond to stop_note
			if (frequency > 0) {
				// start playing the note
				start_note(frequency);

			} else {
				stop_note();
			}

			if (parse_ret_val > 0) {
				// continue playing
				_play_tone = true;
			}
		}

	} else {
		// schedule a call with the tunes max interval
		duration = _tunes.get_maximum_update_interval();
		// stop playing the last note after the duration elapsed
		stop_note();
	}

	// and arrange a callback when the note should stop
	assert(duration != 0);
	_note_call = {};
	hrt_call_after(&_note_call, (hrt_abstime) duration, (hrt_callout)next_trampoline, this);
}

void ToneAlarm::next_trampoline(void *arg)
{
	ToneAlarm *ta = (ToneAlarm *)arg;
	ta->next_note();
}

/**
 * Local functions in support of the shell command.
 */
namespace
{

ToneAlarm	*g_dev;

} // namespace

void tone_alarm_usage();

void tone_alarm_usage()
{
	PX4_INFO("missing command, try 'start', status, 'stop'");
}

int tone_alarm_main(int argc, char *argv[])
{

	if (argc > 1) {
		const char *argv1 = argv[1];

		if (!strcmp(argv1, "start")) {
			if (g_dev != nullptr) {
				PX4_ERR("already started");
				exit(1);
			}

			if (g_dev == nullptr) {
				g_dev = new ToneAlarm();

				if (g_dev == nullptr) {
					PX4_ERR("couldn't allocate the ToneAlarm driver");
					exit(1);
				}

				if (OK != g_dev->init()) {
					delete g_dev;
					g_dev = nullptr;
					PX4_ERR("ToneAlarm init failed");
					exit(1);
				}
			}

			exit(0);
		}

		if (!strcmp(argv1, "stop")) {
			delete g_dev;
			g_dev = nullptr;
			exit(0);
		}

		if (!strcmp(argv1, "status")) {
			g_dev->status();
			exit(0);
		}

	}

	tone_alarm_usage();
	exit(0);
}
<commit_msg>posix:tonealrmsim: use workqueue<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013, 2017-2018 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/*
 * Simulated Low Level Driver for the PX4 audio alarm port. Subscribes to
 * tune_control and plays notes on this architecture specific
 * timer HW
 */

#include <px4_config.h>
#include <px4_posix.h>

#include <drivers/device/device.h>
#include <drivers/drv_tone_alarm.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>

#include <board_config.h>
#include <drivers/drv_hrt.h>

#include <systemlib/err.h>
#include <circuit_breaker/circuit_breaker.h>

#include <px4_workqueue.h>

#include <lib/tunes/tunes.h>
#include <uORB/uORB.h>
#include <uORB/topics/tune_control.h>

#include "VirtDevObj.hpp"

using namespace DriverFramework;

#if !defined(UNUSED)
#  define UNUSED(a) ((void)(a))
#endif

#define CBRK_BUZZER_KEY 782097

class ToneAlarm : public VirtDevObj
{
public:
	ToneAlarm();
	~ToneAlarm();

	virtual int init();
	void status();

	enum {
		CBRK_OFF = 0,
		CBRK_ON,
		CBRK_UNINIT
	};

private:
	volatile bool _running;
	volatile bool _should_run;
	bool _play_tone;

	Tunes _tunes;

	unsigned _silence_length; // if nonzero, silence before next note

	int _cbrk; ///< if true, no audio output
	int _tune_control_sub;

	tune_control_s _tune;

	static work_s _work;

	// Convert a frequency value into a divisor for the configured timer's clock.
	//
	unsigned frequency_to_divisor(unsigned frequency);

	// Start playing the note
	//
	void start_note(unsigned frequency);

	// Stop playing the current note and make the player 'safe'
	//
	void stop_note();

	// Parse the next note out of the string and play it
	//
	void next_note();

	// work queue trampoline for next_note
	//
	static void next_trampoline(void *arg);

	// Unused
	virtual void _measure() {}
};

struct work_s ToneAlarm::_work = {};

/*
 * Driver 'main' command.
 */
extern "C" __EXPORT int tone_alarm_main(int argc, char *argv[]);

ToneAlarm::ToneAlarm() :
	VirtDevObj("tone_alarm", TONEALARM0_DEVICE_PATH, nullptr, 0),
	_running(false),
	_should_run(true),
	_play_tone(false),
	_tunes(),
	_silence_length(0),
	_cbrk(CBRK_UNINIT),
	_tune_control_sub(-1)
{
}

ToneAlarm::~ToneAlarm()
{
	_should_run = false;
	int counter = 0;

	while (_running && ++counter < 10) {
		usleep(100000);
	}
}

int ToneAlarm::init()
{
	int ret;

	ret = VirtDevObj::init();

	if (ret != OK) {
		return ret;
	}

	_running = true;
	work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, 0);
	return OK;
}

void ToneAlarm::status()
{
	if (_running) {
		PX4_INFO("running");

	} else {
		PX4_INFO("stopped");
	}
}

unsigned ToneAlarm::frequency_to_divisor(unsigned frequency)
{
	const int TONE_ALARM_CLOCK = 120000000ul / 4;

	float period = 0.5f / frequency;

	// and the divisor, rounded to the nearest integer
	unsigned divisor = (period * TONE_ALARM_CLOCK) + 0.5f;

	return divisor;
}

void ToneAlarm::start_note(unsigned frequency)
{
	// check if circuit breaker is enabled
	if (_cbrk == CBRK_UNINIT) {
		_cbrk = circuit_breaker_enabled("CBRK_BUZZER", CBRK_BUZZER_KEY);
	}

	if (_cbrk != CBRK_OFF) { return; }

	// compute the divisor
	unsigned divisor = frequency_to_divisor(frequency);

	// pick the lowest prescaler value that we can use
	// (note that the effective prescale value is 1 greater)
	unsigned prescale = divisor / 65536;

	// calculate the timer period for the selected prescaler value
	unsigned period = (divisor / (prescale + 1)) - 1;

	// Silence warning of unused var
	UNUSED(period);
	PX4_DEBUG("ToneAlarm::start_note %u", period);
}

void ToneAlarm::stop_note()
{
}

void ToneAlarm::next_note()
{
	if (!_should_run) {
		if (_tune_control_sub >= 0) {
			orb_unsubscribe(_tune_control_sub);
		}

		_running = false;
		return;
	}

	// subscribe to tune_control
	if (_tune_control_sub < 0) {
		_tune_control_sub = orb_subscribe(ORB_ID(tune_control));
	}

	// do we have an inter-note gap to wait for?
	if (_silence_length > 0) {
		stop_note();
		work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(_silence_length));
		_silence_length = 0;
		return;
	}

	// check for updates
	bool updated = false;
	orb_check(_tune_control_sub, &updated);

	if (updated) {
		orb_copy(ORB_ID(tune_control), _tune_control_sub, &_tune);
	}

	unsigned frequency = 0;
	unsigned duration = 0;

	if (_play_tone) {
		_play_tone = false;
		int parse_ret_val = _tunes.get_next_tune(frequency, duration, _silence_length);

		if (parse_ret_val >= 0) {
			// a frequency of 0 correspond to stop_note
			if (frequency > 0) {
				// start playing the note
				start_note(frequency);

			} else {
				stop_note();
			}

			if (parse_ret_val > 0) {
				// continue playing
				_play_tone = true;
			}
		}

	} else {
		// schedule a call with the tunes max interval
		duration = _tunes.get_maximum_update_interval();
		// stop playing the last note after the duration elapsed
		stop_note();
	}

	// and arrange a callback when the note should stop
	work_queue(HPWORK, &_work, (worker_t)&ToneAlarm::next_trampoline, this, USEC2TICK(duration));
}

void ToneAlarm::next_trampoline(void *arg)
{
	ToneAlarm *ta = (ToneAlarm *)arg;
	ta->next_note();
}

/**
 * Local functions in support of the shell command.
 */
namespace
{

ToneAlarm	*g_dev;

} // namespace

void tone_alarm_usage();

void tone_alarm_usage()
{
	PX4_INFO("missing command, try 'start', status, 'stop'");
}

int tone_alarm_main(int argc, char *argv[])
{

	if (argc > 1) {
		const char *argv1 = argv[1];

		if (!strcmp(argv1, "start")) {
			if (g_dev != nullptr) {
				PX4_ERR("already started");
				exit(1);
			}

			if (g_dev == nullptr) {
				g_dev = new ToneAlarm();

				if (g_dev == nullptr) {
					PX4_ERR("couldn't allocate the ToneAlarm driver");
					exit(1);
				}

				if (OK != g_dev->init()) {
					delete g_dev;
					g_dev = nullptr;
					PX4_ERR("ToneAlarm init failed");
					exit(1);
				}
			}

			exit(0);
		}

		if (!strcmp(argv1, "stop")) {
			delete g_dev;
			g_dev = nullptr;
			exit(0);
		}

		if (!strcmp(argv1, "status")) {
			g_dev->status();
			exit(0);
		}

	}

	tone_alarm_usage();
	exit(0);
}
<|endoftext|>


<commit_before>/*
 * CampSiteActiveAreaImplementation.cpp
 *
 *  Created on: Jan 1, 2012
 *      Author: Kyle
 */

#include "CampSiteActiveArea.h"
#include "CampSiteObserver.h"
#include "server/zone/objects/structure/StructureObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/managers/structure/StructureManager.h"
#include "server/zone/objects/tangible/terminal/Terminal.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/area/events/CampAbandonTask.h"
#include "server/zone/objects/area/events/CampDespawnTask.h"

void CampSiteActiveAreaImplementation::initializeTransientMembers() {
	startTasks();
}

void CampSiteActiveAreaImplementation::init(CampStructureTemplate* campData) {
	campStructureData = campData;
	setRadius(campStructureData->getRadius());
	startTasks();
}

void CampSiteActiveAreaImplementation::startTasks() {
	despawnTask = new CampDespawnTask(_this);
	abandonTask = new CampAbandonTask(_this);
	abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);
	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);
}

void CampSiteActiveAreaImplementation::notifyEnter(SceneObject* object) {
	if (!object->isPlayerCreature())
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	camp->addTemplateSkillMods(player);

	if (campObserver == NULL) {
		campObserver = new CampSiteObserver(_this);
		campObserver->deploy();
	}

	if(object == campOwner && !abandoned) {

		if(abandonTask->isScheduled())
			abandonTask->cancel();

		object->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	} else {

		StringIdChatParameter stringID("camp", "prose_camp_enter");
		stringID.setTO(terminal->getObjectName()->getDisplayedName());
		player->sendSystemMessage(stringID);

		player->sendSystemMessage("@camp:sys_camp_heal");

	}

	if (object->isPlayerCreature() && !visitors.contains(object->getObjectID()))
		visitors.add(object->getObjectID());

	if (object->isPlayerCreature())
		object->registerObserver(ObserverEventType::HEALINGPERFORMED, campObserver);
}

void CampSiteActiveAreaImplementation::notifyExit(SceneObject* object) {
	object->dropObserver(ObserverEventType::HEALINGPERFORMED, campObserver);

	if (!object->isPlayerCreature())
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	camp->removeTemplateSkillMods(player);

	if(abandoned || object != campOwner) {
		StringIdChatParameter stringID("camp", "prose_camp_exit");
		stringID.setTO(terminal->getObjectName()->getDisplayedName());
		player->sendSystemMessage(stringID);
		return;
	}

	if(!abandoned && abandonTask != NULL) {
		abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);
	}
}

int CampSiteActiveAreaImplementation::notifyHealEvent(int64 quantity) {
	// Increase XP Pool for heals
	currentXp += 5;
	return 1;
}

int CampSiteActiveAreaImplementation::notifyCombatEvent() {
	abandonCamp();

	if(abandonTask != NULL)
		if(abandonTask->isScheduled())
			abandonTask->cancel();

	if(campOwner != NULL)
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp");

	return 1;
}

void CampSiteActiveAreaImplementation::abandonCamp() {
	abandoned = true;

	currentXp = 0;

	if(despawnTask != NULL && despawnTask->isScheduled()) {
		despawnTask->cancel();
		int newTime = (CampSiteActiveArea::DESPAWNTIME / 6);
		int maxTime = CampSiteActiveArea::DESPAWNTIME - ((System::getTime() - timeCreated) * 1000);

		despawnTask->schedule(newTime < maxTime ? newTime : maxTime);
	}

	if(terminal != NULL)
		terminal->setCustomObjectName("Abandoned Camp", true);

	if(campOwner != NULL) {
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp");
	}
}

bool CampSiteActiveAreaImplementation::despawnCamp() {

	if(!abandoned && campOwner != NULL && campOwner->getZoneServer() != NULL) {
		/// Get Player Manager
		PlayerManager* playerManager = campOwner->getZoneServer()->getPlayerManager();
		if (playerManager == NULL) {
			error("playerManager is null");
			return false;
		}

		float durationUsed = ((float)(System::getTime() - timeCreated)) / (campStructureData->getDuration());

		int amount = 0;
		amount += (int)(campStructureData->getExperience() * durationUsed);
		amount += ((visitors.size() -1) * 15);
		amount += currentXp;

		int awarded = (amount > campStructureData->getExperience() ? campStructureData->getExperience() : amount);

		playerManager->awardExperience(campOwner, "camp", awarded, true);
	}

	if(despawnTask != NULL ) {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
		despawnTask = NULL;
	}

	if(abandonTask != NULL) {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
		abandonTask = NULL;
	}

	if(campOwner != NULL)
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if(camp->getZone() == NULL)
		return false;

	ManagedReference<StructureManager*> structureManager = camp->getZone()->getStructureManager();
	if (structureManager == NULL) {
		error("Unable to get StructureManager when placing camp");
		return false;
	}

	destroyObjectFromWorld(true);
	destroyObjectFromDatabase(true);
	structureManager->destroyStructure(camp);

	return true;
}

void CampSiteActiveAreaImplementation::assumeOwnership(CreatureObject* player) {

	/// Get Ghost
	PlayerObject* ghost = campOwner->getPlayerObject();

	if (ghost != NULL) {
		ghost->removeOwnedStructure(camp);
	}

	setOwner(player);

	abandoned = false;
	currentXp = 0;

	/// Get Ghost
	ghost = campOwner->getPlayerObject();

	if (ghost != NULL) {
		ghost->addOwnedStructure(camp);
	}

	player->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if(abandonTask != NULL && abandonTask->isScheduled())
		abandonTask->cancel();

	if(terminal != NULL) {
		String campName = player->getFirstName();
		if(!player->getLastName().isEmpty())
			campName += " " + player->getLastName();
		campName += "'s Camp";
		terminal->setCustomObjectName(campName, true);
	}
}
<commit_msg>[Fixed] Camps abandoning after 1 minute<commit_after>/*
 * CampSiteActiveAreaImplementation.cpp
 *
 *  Created on: Jan 1, 2012
 *      Author: Kyle
 */

#include "CampSiteActiveArea.h"
#include "CampSiteObserver.h"
#include "server/zone/objects/structure/StructureObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/managers/structure/StructureManager.h"
#include "server/zone/objects/tangible/terminal/Terminal.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/area/events/CampAbandonTask.h"
#include "server/zone/objects/area/events/CampDespawnTask.h"

void CampSiteActiveAreaImplementation::initializeTransientMembers() {
	startTasks();
}

void CampSiteActiveAreaImplementation::init(CampStructureTemplate* campData) {
	campStructureData = campData;
	setRadius(campStructureData->getRadius());
	startTasks();
}

void CampSiteActiveAreaImplementation::startTasks() {
	if(despawnTask == NULL) {
		despawnTask = new CampDespawnTask(_this);
	} else {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
	}

	if(abandonTask == NULL) {
		abandonTask = new CampAbandonTask(_this);
	} else {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
	}

	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);
	abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);

}

void CampSiteActiveAreaImplementation::notifyEnter(SceneObject* object) {
	if (!object->isPlayerCreature())
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	camp->addTemplateSkillMods(player);

	if (campObserver == NULL) {
		campObserver = new CampSiteObserver(_this);
		campObserver->deploy();
	}

	if(object == campOwner && !abandoned) {

		if(abandonTask->isScheduled())
			abandonTask->cancel();

		object->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	} else {

		StringIdChatParameter stringID("camp", "prose_camp_enter");
		stringID.setTO(terminal->getObjectName()->getDisplayedName());
		player->sendSystemMessage(stringID);

		player->sendSystemMessage("@camp:sys_camp_heal");

	}

	if (object->isPlayerCreature() && !visitors.contains(object->getObjectID()))
		visitors.add(object->getObjectID());

	if (object->isPlayerCreature())
		object->registerObserver(ObserverEventType::HEALINGPERFORMED, campObserver);
}

void CampSiteActiveAreaImplementation::notifyExit(SceneObject* object) {
	object->dropObserver(ObserverEventType::HEALINGPERFORMED, campObserver);

	if (!object->isPlayerCreature())
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	camp->removeTemplateSkillMods(player);

	if(abandoned || object != campOwner) {
		StringIdChatParameter stringID("camp", "prose_camp_exit");
		stringID.setTO(terminal->getObjectName()->getDisplayedName());
		player->sendSystemMessage(stringID);
		return;
	}

	if(!abandoned && abandonTask != NULL) {
		abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);
	}
}

int CampSiteActiveAreaImplementation::notifyHealEvent(int64 quantity) {
	// Increase XP Pool for heals
	currentXp += 5;
	return 1;
}

int CampSiteActiveAreaImplementation::notifyCombatEvent() {
	abandonCamp();

	if(abandonTask != NULL)
		if(abandonTask->isScheduled())
			abandonTask->cancel();

	if(campOwner != NULL)
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp");

	return 1;
}

void CampSiteActiveAreaImplementation::abandonCamp() {
	abandoned = true;

	currentXp = 0;

	if(despawnTask != NULL && despawnTask->isScheduled()) {
		despawnTask->cancel();
		int newTime = (CampSiteActiveArea::DESPAWNTIME / 6);
		int maxTime = CampSiteActiveArea::DESPAWNTIME - ((System::getTime() - timeCreated) * 1000);

		despawnTask->schedule(newTime < maxTime ? newTime : maxTime);
	}

	if(terminal != NULL)
		terminal->setCustomObjectName("Abandoned Camp", true);

	if(campOwner != NULL) {
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp");
	}
}

bool CampSiteActiveAreaImplementation::despawnCamp() {

	if(!abandoned && campOwner != NULL && campOwner->getZoneServer() != NULL) {
		/// Get Player Manager
		PlayerManager* playerManager = campOwner->getZoneServer()->getPlayerManager();
		if (playerManager == NULL) {
			error("playerManager is null");
			return false;
		}

		float durationUsed = ((float)(System::getTime() - timeCreated)) / (campStructureData->getDuration());

		int amount = 0;
		amount += (int)(campStructureData->getExperience() * durationUsed);
		amount += ((visitors.size() -1) * 15);
		amount += currentXp;

		int awarded = (amount > campStructureData->getExperience() ? campStructureData->getExperience() : amount);

		playerManager->awardExperience(campOwner, "camp", awarded, true);
	}

	if(despawnTask != NULL ) {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
		despawnTask = NULL;
	}

	if(abandonTask != NULL) {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
		abandonTask = NULL;
	}

	if(campOwner != NULL)
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if(camp->getZone() == NULL)
		return false;

	ManagedReference<StructureManager*> structureManager = camp->getZone()->getStructureManager();
	if (structureManager == NULL) {
		error("Unable to get StructureManager when placing camp");
		return false;
	}

	destroyObjectFromWorld(true);
	destroyObjectFromDatabase(true);
	structureManager->destroyStructure(camp);

	return true;
}

void CampSiteActiveAreaImplementation::assumeOwnership(CreatureObject* player) {

	/// Get Ghost
	PlayerObject* ghost = campOwner->getPlayerObject();

	if (ghost != NULL) {
		ghost->removeOwnedStructure(camp);
	}

	setOwner(player);

	abandoned = false;
	currentXp = 0;

	/// Get Ghost
	ghost = campOwner->getPlayerObject();

	if (ghost != NULL) {
		ghost->addOwnedStructure(camp);
	}

	player->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if(abandonTask != NULL && abandonTask->isScheduled())
		abandonTask->cancel();

	if(terminal != NULL) {
		String campName = player->getFirstName();
		if(!player->getLastName().isEmpty())
			campName += " " + player->getLastName();
		campName += "'s Camp";
		terminal->setCustomObjectName(campName, true);
	}
}
<|endoftext|>