<commit_before>/* The MIT License

   Copyright (c) 2013 Adrian Tan <atks@umich.edu>

   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 "normalize.h"

namespace
{

class Igor : Program
{
    public:

    ///////////
    //options//
    ///////////
    std::string input_vcf_file;
    std::string output_vcf_file;
    std::vector<GenomeInterval> intervals;
    std::string ref_fasta_file;

    ///////
    //i/o//
    ///////
    BCFOrderedReader *odr;
    BCFOrderedWriter *odw;
    bcf1_t *v;

    kstring_t s;
    kstring_t new_alleles;
    kstring_t old_alleles;

    /////////
    //stats//
    /////////
    uint32_t no_variants;

    uint32_t no_lt;    //# left trimmed
    uint32_t no_lt_la; //# left trimmed and left aligned
    uint32_t no_lt_rt; //# left trimmed and right trimmed
    uint32_t no_la;    //# left aligned
    uint32_t no_rt;    //# right trimmed

    uint32_t no_multi_lt;      //# left trimmed
    uint32_t no_multi_lt_la;   //# left trimmed and left aligned
    uint32_t no_multi_lt_rt;   //# left trimmed and right trimmed
    uint32_t no_multi_la;      //# left aligned
    uint32_t no_multi_rt;      //# right trimmed

    /////////
    //tools//
    /////////
    VariantManip *vm;

    Igor(int argc, char **argv)
    {
        version = "0.5";

        //////////////////////////
        //options initialization//
        //////////////////////////
        try
        {
            std::string desc = "normalizes variants in a VCF file";

            TCLAP::CmdLine cmd(desc, ' ', version);
            VTOutput my; cmd.setOutput(&my);
            TCLAP::ValueArg<std::string> arg_ref_fasta_file("r", "r", "reference sequence fasta file []", true, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_intervals("i", "i", "intervals []", false, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_interval_list("I", "I", "file containing list of intervals []", false, "", "file", cmd);
            TCLAP::ValueArg<std::string> arg_output_vcf_file("o", "o", "output VCF file [-]", false, "-", "str", cmd);
            TCLAP::UnlabeledValueArg<std::string> arg_input_vcf_file("<in.vcf>", "input VCF file", true, "","file", cmd);

            cmd.parse(argc, argv);

            input_vcf_file = arg_input_vcf_file.getValue();
            output_vcf_file = arg_output_vcf_file.getValue();
            parse_intervals(intervals, arg_interval_list.getValue(), arg_intervals.getValue());
            ref_fasta_file = arg_ref_fasta_file.getValue();
        }
        catch (TCLAP::ArgException &e)
        {
            std::cerr << "error: " << e.error() << " for arg " << e.argId() << "\n";
            abort();
        }
    };

    void initialize()
    {
        //////////////////////
        //i/o initialization//
        //////////////////////
        odr = new BCFOrderedReader(input_vcf_file, intervals);

        odw = new BCFOrderedWriter(output_vcf_file, 100000);
        odw->link_hdr(odr->hdr);
        bcf_hdr_append(odw->hdr, "##INFO=<ID=OLD_VARIANT,Number=1,Type=String,Description=\"Original chr:pos:ref:alt encoding\">\n");
        odw->write_hdr();

        s = {0,0,0};
        old_alleles = {0,0,0};
        new_alleles = {0,0,0};

        ////////////////////////
        //stats initialization//
        ////////////////////////
        no_variants = 0;

        no_lt = 0;
        no_lt_la = 0;
        no_lt_rt = 0;
        no_la = 0;
        no_rt = 0;

        no_multi_lt = 0;
        no_multi_lt_la = 0;
        no_multi_lt_rt = 0;
        no_multi_la = 0;
        no_multi_rt = 0;

        ////////////////////////
        //tools initialization//
        ////////////////////////
        vm = new VariantManip(ref_fasta_file);
    }

    void normalize()
    {
        uint32_t left_aligned = 0;
        uint32_t left_trimmed = 0;
        uint32_t right_trimmed = 0;

        int32_t ambiguous_variant_types = (VT_MNP | VT_INDEL | VT_CLUMPED);

        v = odw->get_bcf1_from_pool();
        Variant variant;

        while (odr->read(v))
        {
            bcf_unpack(v, BCF_UN_INFO);
            int32_t vtype = vm->classify_variant(odr->hdr, v, variant);

            if (vtype & ambiguous_variant_types)
            {
                const char* chrom = odr->get_seqname(v);
                uint32_t pos1 = bcf_get_pos1(v);
                std::vector<std::string> alleles;
                for (uint32_t i=0; i<bcf_get_n_allele(v); ++i)
                {
                    alleles.push_back(std::string(bcf_get_alt(v, i)));
                }
                left_aligned = left_trimmed = right_trimmed = 0;

                vm->left_align(alleles, pos1, chrom, left_aligned, right_trimmed);
                vm->left_trim(alleles, pos1, left_trimmed);

                if (left_trimmed || left_aligned || right_trimmed)
                {
                    old_alleles.l = 0;
                    bcf_variant2string(odw->hdr, v, &old_alleles);
                    bcf_update_info_string(odw->hdr, v, "OLD_VARIANT", old_alleles.s);

                    bcf_set_pos1(v, pos1);
                    new_alleles.l=0;
                    for (uint32_t i=0; i<alleles.size(); ++i)
                    {
                        if (i) kputc(',', &new_alleles);
                        kputs(alleles[i].c_str(), &new_alleles);
                    }
                    bcf_update_alleles_str(odr->hdr, v, new_alleles.s);

                    if (bcf_get_n_allele(v)==2)
                    {
                        if (left_trimmed)
                        {
                            if (left_aligned)
                            {
                                ++no_lt_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_lt_rt;
                            }
                            else
                            {
                                ++no_lt;
                            }
                        }
                        else
                        {
                            if (left_aligned)
                            {
                                ++no_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_rt;
                            }
                        }
                    }
                    else
                    {
                        if (left_trimmed)
                        {
                            if (left_aligned)
                            {
                                ++no_multi_lt_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_multi_lt_rt;
                            }
                            else
                            {
                                ++no_multi_lt;
                            }
                        }
                        else
                        {
                            if (left_aligned)
                            {
                                ++no_multi_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_multi_rt;
                            }
                        }
                    }
                }
            }

            ++no_variants;

            odw->write(v);
            v = odw->get_bcf1_from_pool();
        }

        odr->close();
        odw->close();
    };

    void print_options()
    {
        std::clog << "normalize v" << version << "\n\n";

        std::clog << "options:     input VCF file        " << input_vcf_file << "\n";
        std::clog << "         [o] output VCF file       " << output_vcf_file << "\n";
        std::clog << "         [r] reference FASTA file  " << ref_fasta_file << "\n";
        print_int_op("         [i] intervals             ", intervals);
        std::clog << "\n";
    }

    void print_stats()
    {
        std::clog << "\nstats: biallelic\n";
        std::clog << "          no. left trimmed                      : " << no_lt << "\n";
        std::clog << "          no. left trimmed and left aligned     : " << no_lt_la << "\n";
        std::clog << "          no. left trimmed and right trimmed    : " << no_lt_rt << "\n";
        std::clog << "          no. left aligned                      : " << no_la << "\n";
        std::clog << "          no. right trimmed                     : " << no_rt << "\n";
        std::clog << "\n";
        std::clog << "       multiallelic\n";
        std::clog << "          no. left trimmed                      : " << no_multi_lt << "\n";
        std::clog << "          no. left trimmed and left aligned     : " << no_multi_lt_la << "\n";
        std::clog << "          no. left trimmed and right trimmed    : " << no_multi_lt_rt << "\n";
        std::clog << "          no. left aligned                      : " << no_multi_la << "\n";
        std::clog << "          no. right trimmed                     : " << no_multi_rt << "\n";
        std::clog << "\n";
        std::clog << "       no. variants observed                    : " << no_variants << "\n";
        std::clog << "\n";
    };

    ~Igor() {};

    private:
};

}

void normalize(int argc, char ** argv)
{
    Igor igor(argc, argv);
    igor.print_options();
    igor.initialize();
    igor.normalize();
    igor.print_stats();
};
<commit_msg>fixed a benign bug.<commit_after>/* The MIT License

   Copyright (c) 2013 Adrian Tan <atks@umich.edu>

   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 "normalize.h"

namespace
{

class Igor : Program
{
    public:

    ///////////
    //options//
    ///////////
    std::string input_vcf_file;
    std::string output_vcf_file;
    std::vector<GenomeInterval> intervals;
    std::string ref_fasta_file;

    ///////
    //i/o//
    ///////
    BCFOrderedReader *odr;
    BCFOrderedWriter *odw;
    bcf1_t *v;

    kstring_t s;
    kstring_t new_alleles;
    kstring_t old_alleles;

    /////////
    //stats//
    /////////
    uint32_t no_variants;

    uint32_t no_lt;    //# left trimmed
    uint32_t no_lt_la; //# left trimmed and left aligned
    uint32_t no_lt_rt; //# left trimmed and right trimmed
    uint32_t no_la;    //# left aligned
    uint32_t no_rt;    //# right trimmed

    uint32_t no_multi_lt;      //# left trimmed
    uint32_t no_multi_lt_la;   //# left trimmed and left aligned
    uint32_t no_multi_lt_rt;   //# left trimmed and right trimmed
    uint32_t no_multi_la;      //# left aligned
    uint32_t no_multi_rt;      //# right trimmed

    /////////
    //tools//
    /////////
    VariantManip *vm;

    Igor(int argc, char **argv)
    {
        version = "0.5";

        //////////////////////////
        //options initialization//
        //////////////////////////
        try
        {
            std::string desc = "normalizes variants in a VCF file";

            TCLAP::CmdLine cmd(desc, ' ', version);
            VTOutput my; cmd.setOutput(&my);
            TCLAP::ValueArg<std::string> arg_ref_fasta_file("r", "r", "reference sequence fasta file []", true, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_intervals("i", "i", "intervals []", false, "", "str", cmd);
            TCLAP::ValueArg<std::string> arg_interval_list("I", "I", "file containing list of intervals []", false, "", "file", cmd);
            TCLAP::ValueArg<std::string> arg_output_vcf_file("o", "o", "output VCF file [-]", false, "-", "str", cmd);
            TCLAP::UnlabeledValueArg<std::string> arg_input_vcf_file("<in.vcf>", "input VCF file", true, "","file", cmd);

            cmd.parse(argc, argv);

            input_vcf_file = arg_input_vcf_file.getValue();
            output_vcf_file = arg_output_vcf_file.getValue();
            parse_intervals(intervals, arg_interval_list.getValue(), arg_intervals.getValue());
            ref_fasta_file = arg_ref_fasta_file.getValue();
        }
        catch (TCLAP::ArgException &e)
        {
            std::cerr << "error: " << e.error() << " for arg " << e.argId() << "\n";
            abort();
        }
    };

    void initialize()
    {
        //////////////////////
        //i/o initialization//
        //////////////////////
        odr = new BCFOrderedReader(input_vcf_file, intervals);

        odw = new BCFOrderedWriter(output_vcf_file, 100000);
        odw->link_hdr(odr->hdr);
        bcf_hdr_append(odw->hdr, "##INFO=<ID=OLD_VARIANT,Number=1,Type=String,Description=\"Original chr:pos:ref:alt encoding\">\n");
        odw->write_hdr();

        s = {0,0,0};
        old_alleles = {0,0,0};
        new_alleles = {0,0,0};

        ////////////////////////
        //stats initialization//
        ////////////////////////
        no_variants = 0;

        no_lt = 0;
        no_lt_la = 0;
        no_lt_rt = 0;
        no_la = 0;
        no_rt = 0;

        no_multi_lt = 0;
        no_multi_lt_la = 0;
        no_multi_lt_rt = 0;
        no_multi_la = 0;
        no_multi_rt = 0;

        ////////////////////////
        //tools initialization//
        ////////////////////////
        vm = new VariantManip(ref_fasta_file);
    }

    void normalize()
    {
        uint32_t left_aligned = 0;
        uint32_t left_trimmed = 0;
        uint32_t right_trimmed = 0;

        int32_t ambiguous_variant_types = (VT_MNP | VT_INDEL | VT_CLUMPED);

        v = odw->get_bcf1_from_pool();
        Variant variant;

        while (odr->read(v))
        {
            bcf_unpack(v, BCF_UN_INFO);
            int32_t vtype = vm->classify_variant(odr->hdr, v, variant);

            if (vtype & ambiguous_variant_types)
            {
                const char* chrom = odr->get_seqname(v);
                uint32_t pos1 = bcf_get_pos1(v);
                std::vector<std::string> alleles;
                for (uint32_t i=0; i<bcf_get_n_allele(v); ++i)
                {
                    alleles.push_back(std::string(bcf_get_alt(v, i)));
                }
                left_aligned = left_trimmed = right_trimmed = 0;

                vm->left_align(alleles, pos1, chrom, left_aligned, right_trimmed);
                vm->left_trim(alleles, pos1, left_trimmed);

                if (left_trimmed || left_aligned || right_trimmed)
                {
                    old_alleles.l = 0;
                    bcf_variant2string(odw->hdr, v, &old_alleles);
                    bcf_update_info_string(odw->hdr, v, "OLD_VARIANT", old_alleles.s);

                    bcf_set_pos1(v, pos1);
                    new_alleles.l=0;
                    for (uint32_t i=0; i<alleles.size(); ++i)
                    {
                        if (i) kputc(',', &new_alleles);
                        kputs(alleles[i].c_str(), &new_alleles);
                    }
                    bcf_update_alleles_str(odw->hdr, v, new_alleles.s);

                    if (bcf_get_n_allele(v)==2)
                    {
                        if (left_trimmed)
                        {
                            if (left_aligned)
                            {
                                ++no_lt_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_lt_rt;
                            }
                            else
                            {
                                ++no_lt;
                            }
                        }
                        else
                        {
                            if (left_aligned)
                            {
                                ++no_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_rt;
                            }
                        }
                    }
                    else
                    {
                        if (left_trimmed)
                        {
                            if (left_aligned)
                            {
                                ++no_multi_lt_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_multi_lt_rt;
                            }
                            else
                            {
                                ++no_multi_lt;
                            }
                        }
                        else
                        {
                            if (left_aligned)
                            {
                                ++no_multi_la;
                            }
                            else if (right_trimmed)
                            {
                                ++no_multi_rt;
                            }
                        }
                    }
                }
            }

            ++no_variants;

            odw->write(v);
            v = odw->get_bcf1_from_pool();
        }

        odr->close();
        odw->close();
    };

    void print_options()
    {
        std::clog << "normalize v" << version << "\n\n";

        std::clog << "options:     input VCF file        " << input_vcf_file << "\n";
        std::clog << "         [o] output VCF file       " << output_vcf_file << "\n";
        std::clog << "         [r] reference FASTA file  " << ref_fasta_file << "\n";
        print_int_op("         [i] intervals             ", intervals);
        std::clog << "\n";
    }

    void print_stats()
    {
        std::clog << "\nstats: biallelic\n";
        std::clog << "          no. left trimmed                      : " << no_lt << "\n";
        std::clog << "          no. left trimmed and left aligned     : " << no_lt_la << "\n";
        std::clog << "          no. left trimmed and right trimmed    : " << no_lt_rt << "\n";
        std::clog << "          no. left aligned                      : " << no_la << "\n";
        std::clog << "          no. right trimmed                     : " << no_rt << "\n";
        std::clog << "\n";
        std::clog << "       multiallelic\n";
        std::clog << "          no. left trimmed                      : " << no_multi_lt << "\n";
        std::clog << "          no. left trimmed and left aligned     : " << no_multi_lt_la << "\n";
        std::clog << "          no. left trimmed and right trimmed    : " << no_multi_lt_rt << "\n";
        std::clog << "          no. left aligned                      : " << no_multi_la << "\n";
        std::clog << "          no. right trimmed                     : " << no_multi_rt << "\n";
        std::clog << "\n";
        std::clog << "       no. variants observed                    : " << no_variants << "\n";
        std::clog << "\n";
    };

    ~Igor() {};

    private:
};

}

void normalize(int argc, char ** argv)
{
    Igor igor(argc, argv);
    igor.print_options();
    igor.initialize();
    igor.normalize();
    igor.print_stats();
};
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  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 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
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is igor@c-base.org.
//

#include "FilterDistortion.h"

#include <iostream>
#include <math.h>

using namespace std;

namespace avg{

    FilterDistortion::FilterDistortion(const IntPoint& SrcSize,
            CoordTransformerPtr coordtrans)
      : m_SrcSize(SrcSize),
        m_pTrafo(coordtrans)
    {
        //we use the same dimensions for both of src and dest and just crop...
        //for each pixel at (x,y) in the dest
        //m_pMap[x][y] contains a IntPoint that gives the coords in the src Bitmap
        m_pMap = new IntPoint[m_SrcSize.y*m_SrcSize.x];
        for(int y=0; y<m_SrcSize.y; ++y) {
            for(int x=0; x<m_SrcSize.x; ++x) {
                DPoint tmp = m_pTrafo->inverse_transform_point(DPoint(int(x),int(y)));
                IntPoint tmp2(int(tmp.x+0.5),int(tmp.y+0.5));
                if(tmp2.x < m_SrcSize.x && tmp2.y < m_SrcSize.y){
                    m_pMap[y*m_SrcSize.x+x] = tmp2;
                } else {
                    m_pMap[y*m_SrcSize.x+x] = IntPoint(0,0);
                }
            }
        }
    }

    FilterDistortion::~FilterDistortion()
    {
        delete[] m_pMap;
    }

    BitmapPtr FilterDistortion::apply(BitmapPtr pBmpSource)
    {
        BitmapPtr res = BitmapPtr(new Bitmap(m_SrcSize, I8));
        unsigned char *p = res->getPixels();
        unsigned char *src = pBmpSource->getPixels();
        unsigned char *pLine = p;
        int destStride = res->getStride();
        int srcStride = pBmpSource->getStride();
        IntPoint *pMapPos = m_pMap;
        for(int y=0; y<m_SrcSize.y; ++y) {
            for(int x=0; x<m_SrcSize.x; ++x) {
                *pLine = src[pMapPos->x + srcStride*pMapPos->y];
                pLine++;
                pMapPos++;
            }
            p+=destStride;
            pLine = p;
        }
        return res;
    }

}
<commit_msg>Fixed crash in FilterDistortion.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  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 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
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is igor@c-base.org.
//

#include "FilterDistortion.h"

#include <iostream>
#include <math.h>

using namespace std;

namespace avg{

    FilterDistortion::FilterDistortion(const IntPoint& SrcSize,
            CoordTransformerPtr coordtrans)
      : m_SrcSize(SrcSize),
        m_pTrafo(coordtrans)
    {
        //we use the same dimensions for both of src and dest and just crop...
        //for each pixel at (x,y) in the dest
        //m_pMap[x][y] contains a IntPoint that gives the coords in the src Bitmap
        m_pMap = new IntPoint[m_SrcSize.y*m_SrcSize.x];
        for(int y=0; y<m_SrcSize.y; ++y) {
            for(int x=0; x<m_SrcSize.x; ++x) {
                DPoint tmp = m_pTrafo->inverse_transform_point(DPoint(int(x),int(y)));
                IntPoint tmp2(int(tmp.x+0.5),int(tmp.y+0.5));
                if(tmp2.x < m_SrcSize.x && tmp2.y < m_SrcSize.y &&
                        tmp2.x >= 0 && tmp2.y >= 0)
                {
                    m_pMap[y*m_SrcSize.x+x] = tmp2;
                } else {
                    m_pMap[y*m_SrcSize.x+x] = IntPoint(0,0);
                }
            }
        }
    }

    FilterDistortion::~FilterDistortion()
    {
        delete[] m_pMap;
    }

    BitmapPtr FilterDistortion::apply(BitmapPtr pBmpSource)
    {
        BitmapPtr res = BitmapPtr(new Bitmap(m_SrcSize, I8));
        unsigned char *p = res->getPixels();
        unsigned char *src = pBmpSource->getPixels();
        unsigned char *pLine = p;
        int destStride = res->getStride();
        int srcStride = pBmpSource->getStride();
        IntPoint *pMapPos = m_pMap;
        for(int y=0; y<m_SrcSize.y; ++y) {
            for(int x=0; x<m_SrcSize.x; ++x) {
                *pLine = src[pMapPos->x + srcStride*pMapPos->y];
                pLine++;
                pMapPos++;
            }
            p+=destStride;
            pLine = p;
        }
        return res;
    }

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mapnode_p.h"
#include "qgeomap_p.h"
#include <Qt3D/qglpainter.h>
#include <Qt3D/QGLFramebufferObjectSurface>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/private/qsgtexture_p.h>

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif

MapNode::MapNode(QGeoMap *map): QSGGeometryNode(),
        m_fbo(0),
        m_fboSurface(0),
        m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
        m_texture(0),
        m_map(map),
        m_initialized(false),
        m_dirtyFBO(false)
{
    setMaterial(&m_material);
    setOpaqueMaterial(&m_opaqueMaterial);
    setGeometry(&m_geometry);
    // setFlag(UsePreprocess);
}

MapNode::~MapNode()
{
    delete m_fboSurface;
    delete m_fbo;
}

void MapNode::saveRenderState()
{
    //TODO: implement me
}

void MapNode::restoreRenderState()
{
    //TODO: implement me
}

void
MapNode::preprocess()
{
    restoreRenderState();
    //TODO: implement me , texture update
    saveRenderState();
}

void MapNode::update()
{
    restoreRenderState();

    if (!m_initialized)
        init();

    if (m_dirtyFBO)
        updateFBO();

    saveRenderState();
}

void MapNode::updateFBO()
{
    QGLPainter painter;

    if (!painter.begin()) {
        qWarning() << "GL graphics system is not active, can not update FBO for map";
        return;
    }

    painter.pushSurface(m_fboSurface);

    glClearColor(0.9, 0.9, 0.9, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    painter.disableEffect();
#ifdef GL_RESCALE_NORMAL
    // Scale normals by a scale factor derived from modelview matrix.
    // Note: normals need to be unit length.
    glEnable(GL_RESCALE_NORMAL);
#endif

#if !defined(QT_OPENGL_ES_2)
    glShadeModel(GL_SMOOTH);
    glEnable(GL_MULTISAMPLE);
#endif

    // Set the default effect for the scene.
    painter.setStandardEffect(QGL::LitMaterial);
    painter.setFaceColor(QGL::AllFaces, Qt::white);

#if defined(QT_OPENGL_ES)
    glClearDepthf(1);
#else
    glClearDepth(1);
#endif

#if defined(GL_LINE_SMOOTH) && defined(GL_LINE_SMOOTH_HINT)
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
#endif

#ifdef QSGSHADEREFFECTSOURCE_AVAILABLE
    // Update any map objects that may have dirty textures
    for (int i = 0; i < mapItems_.count(); ++i) {
        mapItems_.at(i)->updateItem();
    }
#endif

    // No stereo rendering, set the eye as neutral
    painter.setEye(QGL::NoEye);
    // TODO this needs to be figured out (or confirmed as invalid thing).
    // Currently applied transforms for this Map3D object - how to get/apply current transforms?
    // QTransform transform = painter->combinedTransform();
    // Then we get the rectangle that is gotten by applying the QTransform on the rect
    // --> this is the viewport for Map3D
    // QRect viewport = transform.mapRect(boundingRect()).toRect();

    // boundingRect is in local coordinates. We need to map it to the scene coordinates
    // in order to render to correct area.

    if (m_map->glCamera()) {
        painter.setCamera(m_map->glCamera());
    } else {
        QGLCamera defCamera;
        painter.setCamera(&defCamera);
    }
    m_map->paintGL(&painter);

    restoreDefaults(&painter);

    // Draw the children items
    painter.popSurface();
    // QSG does not expect anyone to alter gl context state; restore defaults.
    // Default heaps of things, because we cannot be sure what the Qt3D internally
    // sets.

#if defined(QT_OPENGL_ES)
    glClearDepthf(0);
#else
    glClearDepth(0);
#endif

    painter.end();

    QSGGeometry::updateTexturedRectGeometry(&m_geometry,
                                            QRectF(QPointF(0, m_fbo->size().height()), QPointF(m_fbo->size().width(), 0)),
                                            QRectF(0, 0, 1, 1));
    delete m_texture;
    m_texture = new QSGPlainTexture();
    m_texture->setOwnsTexture(false);
    m_texture->setTextureSize(m_fbo->size());
    m_texture->setTextureId(m_fbo->texture());
    m_opaqueMaterial.setTexture(m_texture);
    m_material.setTexture(m_texture);
}

void MapNode::setSize(const QSize &size)
{
    if (size == m_size)
        return;
    m_size = size;
    m_dirtyFBO = true;
    m_initialized = false;
    markDirty(DirtyGeometry);
}

void MapNode::init()
{
    delete m_fboSurface;
    delete m_fbo;
    m_fbo = new QOpenGLFramebufferObject(m_size.width(), m_size.height());
    m_fboSurface = new QGLFramebufferObjectSurface(m_fbo);
    m_initialized = true;
}

void MapNode::restoreDefaults(QGLPainter *painter)
{
    // Disable the effect to return control to the GL paint engine.
    painter->disableEffect();

    // Try to restore the default options
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    // Set the default depth buffer options.
    glDepthFunc(GL_LESS);
    glDepthMask(GL_TRUE);
#if defined(QT_OPENGL_ES)
    glDepthRangef(0.0f, 1.0f);
#else
    glDepthRange(0.0f, 1.0f);
#endif
    // Set the default blend options.
    glDisable(GL_BLEND);
    if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendColor))
        painter->glBlendColor(0, 0, 0, 0);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquation))
        painter->glBlendEquation(GL_FUNC_ADD);
    else if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate))
        painter->glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
}

<commit_msg>Add missing call to markDirty() in MapNode::updateFBO()<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mapnode_p.h"
#include "qgeomap_p.h"
#include <Qt3D/qglpainter.h>
#include <Qt3D/QGLFramebufferObjectSurface>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/private/qsgtexture_p.h>

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE 0x809D
#endif

MapNode::MapNode(QGeoMap *map): QSGGeometryNode(),
        m_fbo(0),
        m_fboSurface(0),
        m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
        m_texture(0),
        m_map(map),
        m_initialized(false),
        m_dirtyFBO(false)
{
    setMaterial(&m_material);
    setOpaqueMaterial(&m_opaqueMaterial);
    setGeometry(&m_geometry);
    // setFlag(UsePreprocess);
}

MapNode::~MapNode()
{
    delete m_fboSurface;
    delete m_fbo;
}

void MapNode::saveRenderState()
{
    //TODO: implement me
}

void MapNode::restoreRenderState()
{
    //TODO: implement me
}

void
MapNode::preprocess()
{
    restoreRenderState();
    //TODO: implement me , texture update
    saveRenderState();
}

void MapNode::update()
{
    restoreRenderState();

    if (!m_initialized)
        init();

    if (m_dirtyFBO)
        updateFBO();

    saveRenderState();
}

void MapNode::updateFBO()
{
    QGLPainter painter;

    if (!painter.begin()) {
        qWarning() << "GL graphics system is not active, can not update FBO for map";
        return;
    }

    painter.pushSurface(m_fboSurface);

    glClearColor(0.9, 0.9, 0.9, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    painter.disableEffect();
#ifdef GL_RESCALE_NORMAL
    // Scale normals by a scale factor derived from modelview matrix.
    // Note: normals need to be unit length.
    glEnable(GL_RESCALE_NORMAL);
#endif

#if !defined(QT_OPENGL_ES_2)
    glShadeModel(GL_SMOOTH);
    glEnable(GL_MULTISAMPLE);
#endif

    // Set the default effect for the scene.
    painter.setStandardEffect(QGL::LitMaterial);
    painter.setFaceColor(QGL::AllFaces, Qt::white);

#if defined(QT_OPENGL_ES)
    glClearDepthf(1);
#else
    glClearDepth(1);
#endif

#if defined(GL_LINE_SMOOTH) && defined(GL_LINE_SMOOTH_HINT)
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
#endif

#ifdef QSGSHADEREFFECTSOURCE_AVAILABLE
    // Update any map objects that may have dirty textures
    for (int i = 0; i < mapItems_.count(); ++i) {
        mapItems_.at(i)->updateItem();
    }
#endif

    // No stereo rendering, set the eye as neutral
    painter.setEye(QGL::NoEye);
    // TODO this needs to be figured out (or confirmed as invalid thing).
    // Currently applied transforms for this Map3D object - how to get/apply current transforms?
    // QTransform transform = painter->combinedTransform();
    // Then we get the rectangle that is gotten by applying the QTransform on the rect
    // --> this is the viewport for Map3D
    // QRect viewport = transform.mapRect(boundingRect()).toRect();

    // boundingRect is in local coordinates. We need to map it to the scene coordinates
    // in order to render to correct area.

    if (m_map->glCamera()) {
        painter.setCamera(m_map->glCamera());
    } else {
        QGLCamera defCamera;
        painter.setCamera(&defCamera);
    }
    m_map->paintGL(&painter);

    restoreDefaults(&painter);

    // Draw the children items
    painter.popSurface();
    // QSG does not expect anyone to alter gl context state; restore defaults.
    // Default heaps of things, because we cannot be sure what the Qt3D internally
    // sets.

#if defined(QT_OPENGL_ES)
    glClearDepthf(0);
#else
    glClearDepth(0);
#endif

    painter.end();

    QSGGeometry::updateTexturedRectGeometry(&m_geometry,
                                            QRectF(QPointF(0, m_fbo->size().height()), QPointF(m_fbo->size().width(), 0)),
                                            QRectF(0, 0, 1, 1));
    delete m_texture;
    m_texture = new QSGPlainTexture();
    m_texture->setOwnsTexture(false);
    m_texture->setTextureSize(m_fbo->size());
    m_texture->setTextureId(m_fbo->texture());
    m_opaqueMaterial.setTexture(m_texture);
    m_material.setTexture(m_texture);

    markDirty(DirtyMaterial);
}

void MapNode::setSize(const QSize &size)
{
    if (size == m_size)
        return;
    m_size = size;
    m_dirtyFBO = true;
    m_initialized = false;
    markDirty(DirtyGeometry);
}

void MapNode::init()
{
    delete m_fboSurface;
    delete m_fbo;
    m_fbo = new QOpenGLFramebufferObject(m_size.width(), m_size.height());
    m_fboSurface = new QGLFramebufferObjectSurface(m_fbo);
    m_initialized = true;
}

void MapNode::restoreDefaults(QGLPainter *painter)
{
    // Disable the effect to return control to the GL paint engine.
    painter->disableEffect();

    // Try to restore the default options
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    // Set the default depth buffer options.
    glDepthFunc(GL_LESS);
    glDepthMask(GL_TRUE);
#if defined(QT_OPENGL_ES)
    glDepthRangef(0.0f, 1.0f);
#else
    glDepthRange(0.0f, 1.0f);
#endif
    // Set the default blend options.
    glDisable(GL_BLEND);
    if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendColor))
        painter->glBlendColor(0, 0, 0, 0);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquation))
        painter->glBlendEquation(GL_FUNC_ADD);
    else if (painter->hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate))
        painter->glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
}

<|endoftext|>


<commit_before>#include "include/vkalloc.h"

#include <vector>
#include <unordered_map>

#ifndef VKA_ALLOC_SIZE
#define VKA_ALLOC_SIZE 1024*1024*32
#endif

namespace vka {
    struct Node {
        Node* next = nullptr;
        uint64_t offset = 0;
        uint64_t size = 0;
    };

    struct Page {
        VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
        Node* head = nullptr;
    };

    struct Heap {
        std::vector<Page> pages;
    };

    struct PageMapping {
        uint32_t heapIndex;
        uint32_t pageIndex;
    };

    VkDevice device;
    VkPhysicalDeviceMemoryProperties properties;
    VkAllocationCallbacks* callbacks;
    std::unordered_map<VkDeviceMemory, PageMapping> pageMap;    //caches index into one of the vector<Page> heaps
    std::vector<Heap> heaps;
}

void vkaInit(VkPhysicalDevice physicalDevice, VkDevice device, VkAllocationCallbacks* allocator){
    vka::device = device;
    vka::callbacks = allocator;

    vkGetPhysicalDeviceMemoryProperties(physicalDevice, &vka::properties);

    vka::heaps.resize(vka::properties.memoryHeapCount);
}

using namespace vka;
static VkAllocation AttemptAlloc(uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements);
static VkAllocation AttemptAlloc(Page& page, VkMemoryRequirements requirements);
static Page* AllocNewPage(std::vector<Page>& heap, uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements);
static void Split(Node* current, Node** last, uint64_t start, uint64_t size);
static void Free(VkAllocation allocation, Page& page);
static void Merge(VkAllocation allocation, Node* current);

void vkaTerminate(){
    pageMap.clear();

    for (auto& heap : heaps) {
        for (auto& page : heap.pages) {
            Node* current = page.head;

            while (current){
                Node* next = current->next;
                delete current;
                current = next;
            }

            vkFreeMemory(device, page.deviceMemory, callbacks);
        }

        heap.pages.clear();
    }

    heaps.clear();
}

VkAllocation vkaAlloc(VkMemoryRequirements requirements, VkMemoryPropertyFlags flags) {
    for (size_t i = 0; i < properties.memoryTypeCount; i++) {
        if ((requirements.memoryTypeBits & (1 << i))
            && (properties.memoryTypes[i].propertyFlags & flags) == flags) {
            uint32_t heapIndex = properties.memoryTypes[i].heapIndex;

            VkAllocation result = AttemptAlloc(static_cast<uint32_t>(i), heapIndex, requirements);
            if (result.deviceMemory != VK_NULL_HANDLE) {
                return result;
            }
        }
    }

    return {};
}

void vkaFree(VkAllocation allocation){
    if (allocation.deviceMemory == VK_NULL_HANDLE) return;

    PageMapping& mapping = pageMap[allocation.deviceMemory];
    Page& page = heaps[mapping.heapIndex].pages[mapping.pageIndex];

    Free(allocation, page);
}

static VkAllocation AttemptAlloc(uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements) {
    std::vector<Page>& pages = heaps[heapIndex].pages;

    //attempt to allocate from existing pages
    for (Page& page : pages) {
        VkAllocation result = AttemptAlloc(page, requirements);
        if (result.deviceMemory != VK_NULL_HANDLE) {
            return result;
        }
    }

    //attempt to allocate from new page
    Page* newPage = AllocNewPage(pages, typeIndex, heapIndex, requirements);
    if (newPage) {
        VkAllocation result = AttemptAlloc(*newPage, requirements);
        if (result.deviceMemory != VK_NULL_HANDLE) {
            return result;
        }
    }

    //give up
    return {};
}

static VkAllocation AttemptAlloc(Page& page, VkMemoryRequirements requirements) {
    Node* current = page.head;
    Node** last = &page.head;

    while (current) {
        uint64_t start = current->offset;
        uint64_t available = current->size;

        uint64_t unalign = (start % requirements.alignment);
        uint64_t align;

        if (unalign == 0) {
            align = 0;
        } else {
            align = requirements.alignment - unalign;
        }

        start += align;
        available -= align;

        if (available >= requirements.size) {
            Split(current, last, start, requirements.size);
            VkAllocation result;
            result.deviceMemory = page.deviceMemory;
            result.offset = start;
            result.size = requirements.size;
            return result;
        }

        last = &(current->next);
        current = current->next;
    }

    return {};
}

static void Split(Node* current, Node** last, uint64_t start, uint64_t size) {
    uint64_t startSpace = start - current->offset;
    uint64_t endSpace = current->size - (start + size);

    if (startSpace == 0 && endSpace == 0) {
        *last = current->next;
        delete current;
    } else if (startSpace == 0 && endSpace > 0) {
        current->offset = start + size;
        current->size = endSpace;
    } else if (startSpace > 0 && endSpace == 0) {
        current->size = startSpace;
    } else {    //startSpace > 0 && endSpace > 0
        Node* newNode = new Node;
        newNode->next = current->next;
        newNode->offset = start + size;
        newNode->size = endSpace;

        current->next = newNode;
        current->size = startSpace;
    }
}

static Page* AllocNewPage(std::vector<Page>& heap, uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements) {
    uint64_t allocSize = VKA_ALLOC_SIZE;
    if (requirements.size > allocSize) {
        allocSize = requirements.size;
    }

    VkMemoryAllocateInfo info = {};
    info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    info.allocationSize = allocSize;
    info.memoryTypeIndex = typeIndex;

    VkDeviceMemory memory;
    VkResult result = vkAllocateMemory(device, &info, callbacks, &memory);

    if (result == VK_SUCCESS){
        Node* node = new Node;
        node->size = allocSize;

        Page page = {};
        page.deviceMemory = memory;
        page.head = node;

        heap.emplace_back(page);
        uint32_t pageIndex = static_cast<uint32_t>(heap.size() - 1);

        pageMap[memory] = {heapIndex, pageIndex};

        return &(heap[pageIndex]);
    } else {
        //TODO: add way for user to check the error
        return nullptr;
    }
}

static void Free(VkAllocation allocation, Page& page) {
    Node* current = page.head;

    while (current) {
        if (allocation.offset > current->offset && allocation.offset < current->next->offset) {
            Merge(allocation, current);
            return;
        }

        current = current->next;
    }
}

static void Merge(VkAllocation allocation, Node* current) {
    if (allocation.offset == current->offset + current->size) {
        current->size += allocation.size;
    } else {
        Node* newNode = new Node;
        newNode->next = current->next,
        newNode->offset = allocation.offset,
        newNode->size = allocation.size;

        current = newNode;
    }

    Node* next = current->next;
    if (next->offset == current->offset + current->size) {
        current->size += next->size;
        current->next = next->next;
        delete next;
    }
}<commit_msg>Change vka::Heaps from vector to raw array<commit_after>#include "include/vkalloc.h"

#include <vector>
#include <unordered_map>

#ifndef VKA_ALLOC_SIZE
#define VKA_ALLOC_SIZE 1024*1024*32
#endif

namespace vka {
    struct Node {
        Node* next = nullptr;
        uint64_t offset = 0;
        uint64_t size = 0;
    };

    struct Page {
        VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
        Node* head = nullptr;
    };

    struct Heap {
        std::vector<Page> pages;
    };

    struct PageMapping {
        uint32_t heapIndex;
        uint32_t pageIndex;
    };

    VkDevice device;
    VkPhysicalDeviceMemoryProperties properties;
    VkAllocationCallbacks* callbacks;
    std::unordered_map<VkDeviceMemory, PageMapping> pageMap;    //caches index into one of the vector<Page> heaps
    Heap* heaps;
}

void vkaInit(VkPhysicalDevice physicalDevice, VkDevice device, VkAllocationCallbacks* allocator){
    vka::device = device;
    vka::callbacks = allocator;

    vkGetPhysicalDeviceMemoryProperties(physicalDevice, &vka::properties);

    vka::heaps = new vka::Heap[vka::properties.memoryHeapCount];
}

using namespace vka;
static VkAllocation AttemptAlloc(uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements);
static VkAllocation AttemptAlloc(Page& page, VkMemoryRequirements requirements);
static Page* AllocNewPage(std::vector<Page>& heap, uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements);
static void Split(Node* current, Node** last, uint64_t start, uint64_t size);
static void Free(VkAllocation allocation, Page& page);
static void Merge(VkAllocation allocation, Node* current);

void vkaTerminate(){
    pageMap.clear();

    for (size_t i = 0; i < properties.memoryHeapCount; i++) {
        Heap& heap = heaps[i];
        for (auto& page : heap.pages) {
            Node* current = page.head;

            while (current){
                Node* next = current->next;
                delete current;
                current = next;
            }

            vkFreeMemory(device, page.deviceMemory, callbacks);
        }

        heap.pages.clear();
    }

    delete heaps;
}

VkAllocation vkaAlloc(VkMemoryRequirements requirements, VkMemoryPropertyFlags flags) {
    for (size_t i = 0; i < properties.memoryTypeCount; i++) {
        if ((requirements.memoryTypeBits & (1 << i))
            && (properties.memoryTypes[i].propertyFlags & flags) == flags) {
            uint32_t heapIndex = properties.memoryTypes[i].heapIndex;

            VkAllocation result = AttemptAlloc(static_cast<uint32_t>(i), heapIndex, requirements);
            if (result.deviceMemory != VK_NULL_HANDLE) {
                return result;
            }
        }
    }

    return {};
}

void vkaFree(VkAllocation allocation){
    if (allocation.deviceMemory == VK_NULL_HANDLE) return;

    PageMapping& mapping = pageMap[allocation.deviceMemory];
    Page& page = heaps[mapping.heapIndex].pages[mapping.pageIndex];

    Free(allocation, page);
}

static VkAllocation AttemptAlloc(uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements) {
    Heap& heap = heaps[heapIndex];
    std::vector<Page>& pages = heap.pages;

    //attempt to allocate from existing pages
    for (Page& page : pages) {
        VkAllocation result = AttemptAlloc(page, requirements);
        if (result.deviceMemory != VK_NULL_HANDLE) {
            return result;
        }
    }

    //attempt to allocate from new page
    Page* newPage = AllocNewPage(pages, typeIndex, heapIndex, requirements);
    if (newPage) {
        VkAllocation result = AttemptAlloc(*newPage, requirements);
        if (result.deviceMemory != VK_NULL_HANDLE) {
            return result;
        }
    }

    //give up
    return {};
}

static VkAllocation AttemptAlloc(Page& page, VkMemoryRequirements requirements) {
    Node* current = page.head;
    Node** last = &page.head;

    while (current) {
        uint64_t start = current->offset;
        uint64_t available = current->size;

        uint64_t unalign = (start % requirements.alignment);
        uint64_t align;

        if (unalign == 0) {
            align = 0;
        } else {
            align = requirements.alignment - unalign;
        }

        start += align;
        available -= align;

        if (available >= requirements.size) {
            Split(current, last, start, requirements.size);
            VkAllocation result;
            result.deviceMemory = page.deviceMemory;
            result.offset = start;
            result.size = requirements.size;
            return result;
        }

        last = &(current->next);
        current = current->next;
    }

    return {};
}

static void Split(Node* current, Node** last, uint64_t start, uint64_t size) {
    uint64_t startSpace = start - current->offset;
    uint64_t endSpace = current->size - (start + size);

    if (startSpace == 0 && endSpace == 0) {
        *last = current->next;
        delete current;
    } else if (startSpace == 0 && endSpace > 0) {
        current->offset = start + size;
        current->size = endSpace;
    } else if (startSpace > 0 && endSpace == 0) {
        current->size = startSpace;
    } else {    //startSpace > 0 && endSpace > 0
        Node* newNode = new Node;
        newNode->next = current->next;
        newNode->offset = start + size;
        newNode->size = endSpace;

        current->next = newNode;
        current->size = startSpace;
    }
}

static Page* AllocNewPage(std::vector<Page>& heap, uint32_t typeIndex, uint32_t heapIndex, VkMemoryRequirements requirements) {
    uint64_t allocSize = VKA_ALLOC_SIZE;
    if (requirements.size > allocSize) {
        allocSize = requirements.size;
    }

    VkMemoryAllocateInfo info = {};
    info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    info.allocationSize = allocSize;
    info.memoryTypeIndex = typeIndex;

    VkDeviceMemory memory;
    VkResult result = vkAllocateMemory(device, &info, callbacks, &memory);

    if (result == VK_SUCCESS){
        Node* node = new Node;
        node->size = allocSize;

        Page page = {};
        page.deviceMemory = memory;
        page.head = node;

        heap.emplace_back(page);
        uint32_t pageIndex = static_cast<uint32_t>(heap.size() - 1);

        pageMap[memory] = {heapIndex, pageIndex};

        return &(heap[pageIndex]);
    } else {
        //TODO: add way for user to check the error
        return nullptr;
    }
}

static void Free(VkAllocation allocation, Page& page) {
    Node* current = page.head;

    while (current) {
        if (allocation.offset > current->offset && allocation.offset < current->next->offset) {
            Merge(allocation, current);
            return;
        }

        current = current->next;
    }
}

static void Merge(VkAllocation allocation, Node* current) {
    if (allocation.offset == current->offset + current->size) {
        current->size += allocation.size;
    } else {
        Node* newNode = new Node;
        newNode->next = current->next,
        newNode->offset = allocation.offset,
        newNode->size = allocation.size;

        current = newNode;
    }

    Node* next = current->next;
    if (next->offset == current->offset + current->size) {
        current->size += next->size;
        current->next = next->next;
        delete next;
    }
}<|endoftext|>


<commit_before>#ifndef GUARD_MLOPEN_OCL_KERNEL_HPP_
#define GUARD_MLOPEN_OCL_KERNEL_HPP_

#include <sstream>
#include <array>
#include <utility>
#include <vector>
#include <mlopen.h>
#include <cassert>
#include <functional>
#include <array>
#include <memory>

#include <mlopen/errors.hpp>
#include <mlopen/each_args.hpp>
#include <mlopen/clhelper.hpp>

namespace mlopen {

struct LocalMemArg
{
	LocalMemArg(size_t _size) : size(_size) {}
	size_t GetSize() const { return size; }

	private:
	size_t size;
};

struct OCLSetKernelArg
{
	template<class I, class T>
	void operator()(cl_kernel kernel, I i, const T& x) const
	{
		cl_int status = clSetKernelArg(kernel, (cl_uint)i, sizeof(T), reinterpret_cast<const void*>(&x));
		if (status != CL_SUCCESS) { MLOPEN_THROW("Error setting argument to kernel: " + std::to_string(status));
}
	}

	template<class I, class T>
	void operator()(cl_kernel kernel, I i, const LocalMemArg& lmem) const
	{
		cl_int status = clSetKernelArg(kernel, i, lmem.GetSize(), NULL);
		if (status != CL_SUCCESS) { MLOPEN_THROW("Error setting argument to kernel: " + std::to_string(status));
}
	}
};

struct OCLKernelInvoke
{
	cl_command_queue queue;
	// TODO(paul): Use a pointer to OCLKernel
	cl_kernel kernel;
	size_t work_dim;
	std::array<size_t, 3> global_work_offset;
	std::array<size_t, 3> global_work_dim;
	std::array<size_t, 3> local_work_dim;
	std::function<void(cl_event&)> callback;

	template<class... Ts>
	void operator()(const Ts&... xs) const
	{
		each_args_i(std::bind(OCLSetKernelArg{}, kernel, std::placeholders::_1, std::placeholders::_2), xs...);
		run();
	}

	void run() const;
};

class OCLKernel {

using SharedKernelPtr = std::shared_ptr<typename std::remove_pointer<cl_kernel>::type>;

public:
	OCLKernel() {}
	OCLKernel(ClKernelPtr k) : kernel(std::move(k)) {}
	OCLKernel(ClKernelPtr k,
			std::vector<size_t> local_dims,
			std::vector<size_t> global_dims)
	: kernel(std::move(k)), ldims(std::move(local_dims)), gdims(std::move(global_dims))
	{
		assert(ldims.size() == gdims.size());
		assert(!ldims.empty() && ldims.size() <= 3);
	}

	OCLKernelInvoke Invoke(cl_command_queue q, std::function<void(cl_event&)> callback=nullptr);

	cl_kernel GetKernel() { return kernel.get(); }

	mlopenStatus_t GetKernelName(std::string &progName);

	inline const std::vector<size_t>& GetLocalDims() const { return ldims; }
	inline const std::vector<size_t>& GetGlobalDims() const { return gdims; }

private:
	SharedKernelPtr kernel;
	std::vector<size_t> ldims;
	std::vector<size_t> gdims;
};

}  // namespace mlopen

#endif // GUARD_MLOPEN_OCL_KERNEL_HPP_
<commit_msg>removed cast<commit_after>#ifndef GUARD_MLOPEN_OCL_KERNEL_HPP_
#define GUARD_MLOPEN_OCL_KERNEL_HPP_

#include <sstream>
#include <array>
#include <utility>
#include <vector>
#include <mlopen.h>
#include <cassert>
#include <functional>
#include <array>
#include <memory>

#include <mlopen/errors.hpp>
#include <mlopen/each_args.hpp>
#include <mlopen/clhelper.hpp>

namespace mlopen {

struct LocalMemArg
{
	LocalMemArg(size_t _size) : size(_size) {}
	size_t GetSize() const { return size; }

	private:
	size_t size;
};

struct OCLSetKernelArg
{
	template<class I, class T>
	void operator()(cl_kernel kernel, I i, const T& x) const
	{
		cl_int status = clSetKernelArg(kernel, i, sizeof(T), reinterpret_cast<const void*>(&x));
		if (status != CL_SUCCESS) { MLOPEN_THROW("Error setting argument to kernel: " + std::to_string(status));
}
	}

	template<class I, class T>
	void operator()(cl_kernel kernel, I i, const LocalMemArg& lmem) const
	{
		cl_int status = clSetKernelArg(kernel, i, lmem.GetSize(), NULL);
		if (status != CL_SUCCESS) { MLOPEN_THROW("Error setting argument to kernel: " + std::to_string(status));
}
	}
};

struct OCLKernelInvoke
{
	cl_command_queue queue;
	// TODO(paul): Use a pointer to OCLKernel
	cl_kernel kernel;
	size_t work_dim;
	std::array<size_t, 3> global_work_offset;
	std::array<size_t, 3> global_work_dim;
	std::array<size_t, 3> local_work_dim;
	std::function<void(cl_event&)> callback;

	template<class... Ts>
	void operator()(const Ts&... xs) const
	{
		each_args_i(std::bind(OCLSetKernelArg{}, kernel, std::placeholders::_1, std::placeholders::_2), xs...);
		run();
	}

	void run() const;
};

class OCLKernel {

using SharedKernelPtr = std::shared_ptr<typename std::remove_pointer<cl_kernel>::type>;

public:
	OCLKernel() {}
	OCLKernel(ClKernelPtr k) : kernel(std::move(k)) {}
	OCLKernel(ClKernelPtr k,
			std::vector<size_t> local_dims,
			std::vector<size_t> global_dims)
	: kernel(std::move(k)), ldims(std::move(local_dims)), gdims(std::move(global_dims))
	{
		assert(ldims.size() == gdims.size());
		assert(!ldims.empty() && ldims.size() <= 3);
	}

	OCLKernelInvoke Invoke(cl_command_queue q, std::function<void(cl_event&)> callback=nullptr);

	cl_kernel GetKernel() { return kernel.get(); }

	mlopenStatus_t GetKernelName(std::string &progName);

	inline const std::vector<size_t>& GetLocalDims() const { return ldims; }
	inline const std::vector<size_t>& GetGlobalDims() const { return gdims; }

private:
	SharedKernelPtr kernel;
	std::vector<size_t> ldims;
	std::vector<size_t> gdims;
};

}  // namespace mlopen

#endif // GUARD_MLOPEN_OCL_KERNEL_HPP_
<|endoftext|>


<commit_before>#include <vector>
#include <cmath>

#include "ingameelements/character.h"
#include "gamestate.h"
#include "ingameelements/movingentity.h"
#include "player.h"
#include "global_constants.h"
#include "engine.h"
#include "ingameelements/weapon.h"

Character::Character(uint64_t id_, Gamestate *state, EntityPtr owner_, CharacterChildParameters parameters) : MovingEntity(id_, state),
            owner(owner_), weapon(parameters.weapon), pressed_keys(), held_keys(), lastdirectionpressed(0)
{
    acceleration = 300;
    runpower = parameters.runpower;
    // friction factor per second of null movement; calculated directly from Gang Garrison 2
    // from pygg2
    friction = 0.01510305449388463132584804061124;
}

Character::~Character()
{
    ;
}

void Character::setinput(Gamestate *state, INPUT_CONTAINER pressed_keys_, INPUT_CONTAINER held_keys_, double mouse_x_, double mouse_y_)
{
    pressed_keys = pressed_keys_;
    held_keys = held_keys_;
    mouse_x = mouse_x_;
    mouse_y = mouse_y_;
    Weapon *w = state->get<Weapon>(weapon);
    w->setaim(mouse_x, mouse_y);
}

void Character::beginstep(Gamestate *state, double frametime)
{
    state->get<Weapon>(weapon)->beginstep(state, frametime);
}

void Character::midstep(Gamestate *state, double frametime)
{
    if (cangetinput(state))
    {
        double maxhspeed;
        if (animstate()->crouchanim.active())
        {
            maxhspeed = 60.0;
        }
        else
        {
            maxhspeed = 153.0;
        }

        if (pressed_keys.LEFT)
        {
            lastdirectionpressed = LEFT;
        }
        else if (lastdirectionpressed == LEFT and not held_keys.LEFT)
        {
            lastdirectionpressed = RIGHT*held_keys.RIGHT;
        }
        if (pressed_keys.RIGHT)
        {
            lastdirectionpressed = RIGHT;
        }
        else if (lastdirectionpressed == RIGHT and not held_keys.RIGHT)
        {
            lastdirectionpressed = LEFT*held_keys.LEFT;
        }

        if (lastdirectionpressed == LEFT)
        {
            hspeed = std::max(hspeed - acceleration * runpower * frametime, -maxhspeed);
        }
        else if (lastdirectionpressed == RIGHT)
        {
            hspeed = std::min(hspeed + acceleration * runpower * frametime, maxhspeed);
        }

        if (held_keys.JUMP)
        {
            if (onground(state))
            {
                vspeed = -240.0;
            }
        }
        if (held_keys.CROUCH)
        {
            if (not animstate()->crouchanim.active())
            {
                animstate()->crouchanim.active(true);
                animstate()->crouchanim.reset();
            }
        }
        else if (animstate()->crouchanim.active())
        {
            // We're crouched and we'd like to uncrouch
            // Do so only if we have the room
            if (not state->currentmap->collides(getstandingcollisionrect(state)))
            {
                animstate()->crouchanim.active(false);
            }
        }

        if (held_keys.RELOAD)
        {
            Weapon *w = state->get<Weapon>(weapon);
            w->reload(state, frametime);
        }
        // Shooting
        if (held_keys.PRIMARY_FIRE)
        {
            Weapon *w = state->get<Weapon>(weapon);
            w->fireprimary(state, frametime);
        }
        if (held_keys.SECONDARY_FIRE)
        {
            x = mouse_x;
            y = mouse_y;
            Weapon *w = state->get<Weapon>(weapon);
            w->firesecondary(state, frametime);
        }

        if (animstate()->isflipped != (mouse_x < 0))
        {
            // Spinjumping (compensate for later gravity)
            vspeed -= 540.0*frametime*3.0/4.0;
            animstate()->isflipped = (mouse_x < 0);
        }
    }

    // Gravity
    vspeed += 540.0*frametime;

    // apply friction
    hspeed *= std::pow(friction, frametime);

    state->get<Weapon>(weapon)->midstep(state, frametime);
}

void Character::endstep(Gamestate *state, double frametime)
{
    MovingEntity::endstep(state, frametime);

    // Collision with wallmask
    if (state->currentmap->collides(getcollisionrect(state)))
    {
        // We collide, do collision handling
        double hs = hspeed*frametime, vs = vspeed*frametime;
        // Buffers for "undone" horizontal/vertical movement
        double xbuffer = 0.0, ybuffer = 0.0;
        int steps = std::ceil(std::fmax(std::abs(hs), std::abs(vs)));
        double xstep = hs/steps, ystep = vs/steps;
        // Pull us out of the wall
        for (int i=0; i<steps; ++i)
        {
            x -= xstep; y -= ystep;
            xbuffer += xstep; ybuffer += ystep;
            if (not state->currentmap->collides(getcollisionrect(state)))
            {
                break;
            }
        }
        // We're at the point where the character touched the wallmask for the first time
        // Now keep moving one unit in either direction until all possible movement is exhausted
        bool xblocked = false, yblocked = false;
        bool xfinished = false, yfinished = false;
        double oldxbuffer = xbuffer, oldybuffer = ybuffer;
        while (not xfinished or not yfinished)
        {
            oldxbuffer = xbuffer; oldybuffer = ybuffer;
            // Try first moving horizontally
            if (not xfinished)
            {
                if (not state->currentmap->collides(getcollisionrect(state).offset(xstep, 0)))
                {
                    x += xstep;
                    xbuffer -= xstep;
                    if (xbuffer == 0.0 or std::signbit(xbuffer) != std::signbit(oldxbuffer))
                    {
                        // We're done for this coordinate
                        xfinished = true;
                    }
                }
                else
                {
                    // There's the possibility we might have walked into a staircase
                    if (not state->currentmap->collides(getcollisionrect(state).offset(xstep, STAIRCASE_STEPSIZE)))
                    {
                        // Indeed we did. Move up
                        x += xstep;
                        y += STAIRCASE_STEPSIZE;
                        xbuffer -= xstep;
                        if (xbuffer == 0.0 or std::signbit(xbuffer) != std::signbit(oldxbuffer))
                        {
                            // We're done for this coordinate
                            xfinished = true;
                        }
                    }
                    else
                    {
                        // No more moving, we're blocked
                        xblocked = true;
                        xfinished = true;
                    }
                }
            }
            // Do the same vertically, but without stair code
            if (not yfinished)
            {
                if (not state->currentmap->collides(getcollisionrect(state).offset(0, ystep)))
                {
                    // We cam move through
                    y += ystep;
                    ybuffer -= ystep;
                    if (ybuffer == 0.0 or std::signbit(ybuffer) != std::signbit(oldybuffer))
                    {
                        // We're done for this coordinate
                        yfinished = true;
                    }
                }
                else
                {
                    // No more moving, we're blocked
                    yblocked = true;
                    yfinished = true;
                }
            }
        }
        // Set hspeed and vspeed to what they should be
        if (xblocked)
        {
            hspeed = 0;
        }
        if (yblocked)
        {
            vspeed = 0;
        }
        if (state->currentmap->collides(getcollisionrect(state)))
        {
            printf("\nError: Still in wallmask after collision handling.");
        }
    } // end collision with wallmask

    // Stick to stairs when going down
    if (std::fabs(vspeed*frametime) <= 3.0 and not onground(state))
    {
        Rect r = getcollisionrect(state);
        int stepsize = (-STAIRCASE_STEPSIZE)*std::ceil(std::fabs(hspeed)*frametime/(-STAIRCASE_STEPSIZE));
        if (state->currentmap->collides(Rect(r.x, r.y+r.h+stepsize, r.w, 1)))
        {
            for (int i=0; i<stepsize; ++i)
            {
                ++y;
                if (onground(state))
                {
                    break;
                }
            }
        }
    }

    // Running animation
    if (onground(state))
    {
        if (animstate()->isflipped)
        {
            animstate()->runanim.update(state, -hspeed*frametime);
            animstate()->crouchanim.update(state, -hspeed*frametime);
        }
        else
        {
            animstate()->runanim.update(state, hspeed*frametime);
            animstate()->crouchanim.update(state, hspeed*frametime);
        }
    }
    if (hspeed == 0.0)
    {
        bool run=animstate()->runanim.active(), crouch=animstate()->crouchanim.active();
        animstate()->runanim.reset();
        animstate()->runanim.active(run);
        animstate()->crouchanim.reset();
        animstate()->crouchanim.active(crouch);
    }

    state->get<Weapon>(weapon)->endstep(state, frametime);
}

bool Character::onground(Gamestate *state)
{
    Rect r = getcollisionrect(state);
    return state->currentmap->collides(Rect(r.x, r.y+r.h, r.w, 1));
}

void Character::interpolate(Entity *prev_entity, Entity *next_entity, double alpha)
{
    MovingEntity::interpolate(prev_entity, next_entity, alpha);

    Character *prev_e = static_cast<Character*>(prev_entity);
    Character *next_e = static_cast<Character*>(next_entity);

    if (alpha < 0.5)
    {
        held_keys = prev_e->held_keys;
        pressed_keys = prev_e->pressed_keys;
        animstate()->crouchanim.active(prev_e->animstate()->crouchanim.active());
    }
    else
    {
        held_keys = next_e->held_keys;
        pressed_keys = next_e->pressed_keys;
        animstate()->crouchanim.active(prev_e->animstate()->crouchanim.active());
    }
    mouse_x = prev_e->mouse_x + alpha*(next_e->mouse_x - prev_e->mouse_x);
    mouse_y = prev_e->mouse_y + alpha*(next_e->mouse_y - prev_e->mouse_y);
    animstate()->runanim.interpolate(&(prev_e->animstate()->runanim), &(next_e->animstate()->runanim), alpha);
}
<commit_msg>Fixed jumping.<commit_after>#include <vector>
#include <cmath>

#include "ingameelements/character.h"
#include "gamestate.h"
#include "ingameelements/movingentity.h"
#include "player.h"
#include "global_constants.h"
#include "engine.h"
#include "ingameelements/weapon.h"

Character::Character(uint64_t id_, Gamestate *state, EntityPtr owner_, CharacterChildParameters parameters) : MovingEntity(id_, state),
            owner(owner_), weapon(parameters.weapon), pressed_keys(), held_keys(), lastdirectionpressed(0)
{
    acceleration = 300;
    runpower = parameters.runpower;
    // friction factor per second of null movement; calculated directly from Gang Garrison 2
    // from pygg2
    friction = 0.01510305449388463132584804061124;
}

Character::~Character()
{
    ;
}

void Character::setinput(Gamestate *state, INPUT_CONTAINER pressed_keys_, INPUT_CONTAINER held_keys_, double mouse_x_, double mouse_y_)
{
    pressed_keys = pressed_keys_;
    held_keys = held_keys_;
    mouse_x = mouse_x_;
    mouse_y = mouse_y_;
    Weapon *w = state->get<Weapon>(weapon);
    w->setaim(mouse_x, mouse_y);
}

void Character::beginstep(Gamestate *state, double frametime)
{
    state->get<Weapon>(weapon)->beginstep(state, frametime);
}

void Character::midstep(Gamestate *state, double frametime)
{
    if (cangetinput(state))
    {
        double maxhspeed;
        if (animstate()->crouchanim.active())
        {
            maxhspeed = 60.0;
        }
        else
        {
            maxhspeed = 153.0;
        }

        if (pressed_keys.LEFT)
        {
            lastdirectionpressed = LEFT;
        }
        else if (lastdirectionpressed == LEFT and not held_keys.LEFT)
        {
            lastdirectionpressed = RIGHT*held_keys.RIGHT;
        }
        if (pressed_keys.RIGHT)
        {
            lastdirectionpressed = RIGHT;
        }
        else if (lastdirectionpressed == RIGHT and not held_keys.RIGHT)
        {
            lastdirectionpressed = LEFT*held_keys.LEFT;
        }

        if (lastdirectionpressed == LEFT)
        {
            hspeed = std::max(hspeed - acceleration * runpower * frametime, -maxhspeed);
        }
        else if (lastdirectionpressed == RIGHT)
        {
            hspeed = std::min(hspeed + acceleration * runpower * frametime, maxhspeed);
        }

        if (pressed_keys.JUMP)
        {
            if (onground(state))
            {
                vspeed = -240.0;
            }
        }
        if (held_keys.CROUCH)
        {
            if (not animstate()->crouchanim.active())
            {
                animstate()->crouchanim.active(true);
                animstate()->crouchanim.reset();
            }
        }
        else if (animstate()->crouchanim.active())
        {
            // We're crouched and we'd like to uncrouch
            // Do so only if we have the room
            if (not state->currentmap->collides(getstandingcollisionrect(state)))
            {
                animstate()->crouchanim.active(false);
            }
        }

        if (held_keys.RELOAD)
        {
            Weapon *w = state->get<Weapon>(weapon);
            w->reload(state, frametime);
        }
        // Shooting
        if (held_keys.PRIMARY_FIRE)
        {
            Weapon *w = state->get<Weapon>(weapon);
            w->fireprimary(state, frametime);
        }
        if (held_keys.SECONDARY_FIRE)
        {
            x = mouse_x;
            y = mouse_y;
            Weapon *w = state->get<Weapon>(weapon);
            w->firesecondary(state, frametime);
        }

        if (animstate()->isflipped != (mouse_x < 0))
        {
            // Spinjumping (compensate for later gravity)
            vspeed -= 540.0*frametime*3.0/4.0;
            animstate()->isflipped = (mouse_x < 0);
        }
    }

    // Gravity
    vspeed += 540.0*frametime;

    // apply friction
    hspeed *= std::pow(friction, frametime);

    state->get<Weapon>(weapon)->midstep(state, frametime);
}

void Character::endstep(Gamestate *state, double frametime)
{
    MovingEntity::endstep(state, frametime);

    // Collision with wallmask
    if (state->currentmap->collides(getcollisionrect(state)))
    {
        // We collide, do collision handling
        double hs = hspeed*frametime, vs = vspeed*frametime;
        // Buffers for "undone" horizontal/vertical movement
        double xbuffer = 0.0, ybuffer = 0.0;
        int steps = std::ceil(std::fmax(std::abs(hs), std::abs(vs)));
        double xstep = hs/steps, ystep = vs/steps;
        // Pull us out of the wall
        for (int i=0; i<steps; ++i)
        {
            x -= xstep; y -= ystep;
            xbuffer += xstep; ybuffer += ystep;
            if (not state->currentmap->collides(getcollisionrect(state)))
            {
                break;
            }
        }
        // We're at the point where the character touched the wallmask for the first time
        // Now keep moving one unit in either direction until all possible movement is exhausted
        bool xblocked = false, yblocked = false;
        bool xfinished = false, yfinished = false;
        double oldxbuffer = xbuffer, oldybuffer = ybuffer;
        while (not xfinished or not yfinished)
        {
            oldxbuffer = xbuffer; oldybuffer = ybuffer;
            // Try first moving horizontally
            if (not xfinished)
            {
                if (not state->currentmap->collides(getcollisionrect(state).offset(xstep, 0)))
                {
                    x += xstep;
                    xbuffer -= xstep;
                    if (xbuffer == 0.0 or std::signbit(xbuffer) != std::signbit(oldxbuffer))
                    {
                        // We're done for this coordinate
                        xfinished = true;
                    }
                }
                else
                {
                    // There's the possibility we might have walked into a staircase
                    if (not state->currentmap->collides(getcollisionrect(state).offset(xstep, STAIRCASE_STEPSIZE)))
                    {
                        // Indeed we did. Move up
                        x += xstep;
                        y += STAIRCASE_STEPSIZE;
                        xbuffer -= xstep;
                        if (xbuffer == 0.0 or std::signbit(xbuffer) != std::signbit(oldxbuffer))
                        {
                            // We're done for this coordinate
                            xfinished = true;
                        }
                    }
                    else
                    {
                        // No more moving, we're blocked
                        xblocked = true;
                        xfinished = true;
                    }
                }
            }
            // Do the same vertically, but without stair code
            if (not yfinished)
            {
                if (not state->currentmap->collides(getcollisionrect(state).offset(0, ystep)))
                {
                    // We cam move through
                    y += ystep;
                    ybuffer -= ystep;
                    if (ybuffer == 0.0 or std::signbit(ybuffer) != std::signbit(oldybuffer))
                    {
                        // We're done for this coordinate
                        yfinished = true;
                    }
                }
                else
                {
                    // No more moving, we're blocked
                    yblocked = true;
                    yfinished = true;
                }
            }
        }
        // Set hspeed and vspeed to what they should be
        if (xblocked)
        {
            hspeed = 0;
        }
        if (yblocked)
        {
            vspeed = 0;
        }
        if (state->currentmap->collides(getcollisionrect(state)))
        {
            printf("\nError: Still in wallmask after collision handling.");
        }
    } // end collision with wallmask

    // Stick to stairs when going down
    if (std::fabs(vspeed*frametime) <= 3.0 and not std::signbit(vspeed*frametime) and not onground(state))
    {
        Rect r = getcollisionrect(state);
        int stepsize = (-STAIRCASE_STEPSIZE)*std::ceil(std::fabs(hspeed)*frametime/(-STAIRCASE_STEPSIZE));
        if (state->currentmap->collides(Rect(r.x, r.y+r.h+stepsize, r.w, 1)))
        {
            for (int i=0; i<stepsize; ++i)
            {
                ++y;
                if (onground(state))
                {
                    break;
                }
            }
        }
    }

    // Running animation
    if (onground(state))
    {
        if (animstate()->isflipped)
        {
            animstate()->runanim.update(state, -hspeed*frametime);
            animstate()->crouchanim.update(state, -hspeed*frametime);
        }
        else
        {
            animstate()->runanim.update(state, hspeed*frametime);
            animstate()->crouchanim.update(state, hspeed*frametime);
        }
    }
    if (hspeed == 0.0)
    {
        bool run=animstate()->runanim.active(), crouch=animstate()->crouchanim.active();
        animstate()->runanim.reset();
        animstate()->runanim.active(run);
        animstate()->crouchanim.reset();
        animstate()->crouchanim.active(crouch);
    }

    state->get<Weapon>(weapon)->endstep(state, frametime);
}

bool Character::onground(Gamestate *state)
{
    Rect r = getcollisionrect(state);
    return state->currentmap->collides(Rect(r.x, r.y+r.h, r.w, 1));
}

void Character::interpolate(Entity *prev_entity, Entity *next_entity, double alpha)
{
    MovingEntity::interpolate(prev_entity, next_entity, alpha);

    Character *prev_e = static_cast<Character*>(prev_entity);
    Character *next_e = static_cast<Character*>(next_entity);

    if (alpha < 0.5)
    {
        held_keys = prev_e->held_keys;
        pressed_keys = prev_e->pressed_keys;
        animstate()->crouchanim.active(prev_e->animstate()->crouchanim.active());
    }
    else
    {
        held_keys = next_e->held_keys;
        pressed_keys = next_e->pressed_keys;
        animstate()->crouchanim.active(prev_e->animstate()->crouchanim.active());
    }
    mouse_x = prev_e->mouse_x + alpha*(next_e->mouse_x - prev_e->mouse_x);
    mouse_y = prev_e->mouse_y + alpha*(next_e->mouse_y - prev_e->mouse_y);
    animstate()->runanim.interpolate(&(prev_e->animstate()->runanim), &(next_e->animstate()->runanim), alpha);
}
<|endoftext|>


<commit_before>#include "../../kernel/settingsManager.h"
#include "editorPage.h"
#include "ui_editorPage.h"
#include <QMessageBox>

PreferencesEditorPage::PreferencesEditorPage(QAction * const showGridAction, QAction * const showAlignmentAction
		,QAction * const activateGridAction, QAction * const activateAlignmentAction, QWidget *parent) :
	PreferencesPage(parent),
	mUi(new Ui::PreferencesEditorPage),
	mFontWasChanged(false),
	mFontButtonWasPressed(false),
	mWidthGrid(SettingsManager::value("GridWidth", 10).toInt()),
	mIndexGrid(SettingsManager::value("IndexGrid", 30).toInt()),
	mShowGridAction(showGridAction),
	mShowAlignmentAction(showAlignmentAction),
	mActivateGridAction(activateGridAction),
	mActivateAlignmentAction(activateAlignmentAction)
{
	mUi->setupUi(this);

	// changing grid size in QReal:Robots is forbidden
	connect(mUi->gridWidthSlider, SIGNAL(sliderMoved(int)), this, SLOT(widthGridSliderMoved(int)));
	connect(mUi->indexGridSlider, SIGNAL(sliderMoved(int)), this, SLOT(indexGridSliderMoved(int)));
	connect(mUi->fontCheckBox, SIGNAL(toggled(bool)), this, SLOT(manualFontCheckBoxChecked(bool)));
	connect(mUi->fontSelectionButton, SIGNAL(clicked()),this, SLOT(fontSelectionButtonClicked()));
	mUi->indexGridSlider->setVisible(false);
	mUi->label_20->setVisible(false);

	mUi->showGridCheckBox->setChecked(SettingsManager::value("ShowGrid", true).toBool());
	mUi->showAlignmentCheckBox->setChecked(SettingsManager::value("ShowAlignment", true).toBool());
	mUi->activateGridCheckBox->setChecked(SettingsManager::value("ActivateGrid", false).toBool());
	mUi->activateAlignmentCheckBox->setChecked(SettingsManager::value("ActivateAlignment", true).toBool());
	mUi->embeddedLinkerIndentSlider->setValue(SettingsManager::value("EmbeddedLinkerIndent", 8).toInt());
	mUi->embeddedLinkerSizeSlider->setValue(SettingsManager::value("EmbeddedLinkerSize", 6).toInt());
	mUi->zoomFactorSlider->setValue(SettingsManager::value("zoomFactor", 2).toInt());

	mUi->gridWidthSlider->setValue(mWidthGrid);
	mUi->indexGridSlider->setValue(mIndexGrid);
	mUi->fontCheckBox->setChecked(SettingsManager::value("CustomFont", false).toBool());
	mUi->fontSelectionButton->hide();

	if (SettingsManager::value("CustomFont", false).toBool()) {
		mUi->fontCheckBox->setChecked(true);
		mUi->fontSelectionButton->show();
	}
}

PreferencesEditorPage::~PreferencesEditorPage()
{
	SettingsManager::setValue("GridWidth", mWidthGrid);
	SettingsManager::setValue("IndexGrid", mIndexGrid);

	delete mUi;
}

void PreferencesEditorPage::manualFontCheckBoxChecked(bool state) {
	SettingsManager::setValue("manualFontCheckBoxChecked", state);

	mFontWasChanged = !mFontWasChanged;
	mUi->fontSelectionButton->setVisible(state);
}

void PreferencesEditorPage::fontSelectionButtonClicked() {
	if (!mFontWasChanged)
		mFontWasChanged = !mFontWasChanged;
	mFontButtonWasPressed = true;
	mFontDialog = new QFontDialog();
	mFontDialog->open();
}

void PreferencesEditorPage::changeEvent(QEvent *e)
{
	switch (e->type()) {
	case QEvent::LanguageChange:
		mUi->retranslateUi(this);
		break;
	default:
		break;
	}
}

void PreferencesEditorPage::widthGridSliderMoved(int value)
{
	SettingsManager::setValue("GridWidth", value);
	emit gridChanged();
}

void PreferencesEditorPage::indexGridSliderMoved(int value)
{
	SettingsManager::setValue("IndexGrid", value);
	emit gridChanged();
}

void PreferencesEditorPage::save()
{
	SettingsManager::setValue("EmbeddedLinkerIndent", mUi->embeddedLinkerIndentSlider->value());
	SettingsManager::setValue("EmbeddedLinkerSize", mUi->embeddedLinkerSizeSlider->value());
	SettingsManager::setValue("zoomFactor", mUi->zoomFactorSlider->value());
	SettingsManager::setValue("ShowGrid", mUi->showGridCheckBox->isChecked());
	SettingsManager::setValue("ShowAlignment", mUi->showAlignmentCheckBox->isChecked());
	SettingsManager::setValue("ActivateGrid", mUi->activateGridCheckBox->isChecked());
	SettingsManager::setValue("ActivateAlignment", mUi->activateAlignmentCheckBox->isChecked());
	SettingsManager::setValue("CustomFont", mUi->fontCheckBox->isChecked());

	mWidthGrid = mUi->gridWidthSlider->value();
	mIndexGrid = mUi->indexGridSlider->value();
	SettingsManager::setValue("GridWidth", mWidthGrid);
	SettingsManager::setValue("IndexGrid", mIndexGrid);

	mShowGridAction->setChecked(mUi->showGridCheckBox->isChecked());
	mShowAlignmentAction->setChecked(mUi->showAlignmentCheckBox->isChecked());
	mActivateGridAction->setChecked(mUi->activateGridCheckBox->isChecked());
	mActivateAlignmentAction->setChecked(mUi->activateAlignmentCheckBox->isChecked());

	if (mFontWasChanged) {
		if (mFontButtonWasPressed)
			SettingsManager::setValue("CurrentFont", mFontDialog->currentFont().toString());
		QMessageBox::information(NULL, "Information", "You should restart QReal:Robots to apply changes", "ok");
		mFontWasChanged = false;
		mFontButtonWasPressed = false;
	}
}
<commit_msg>Added modality for FontDialog. Closed #151.<commit_after>#include "../../kernel/settingsManager.h"
#include "editorPage.h"
#include "ui_editorPage.h"
#include <QMessageBox>

PreferencesEditorPage::PreferencesEditorPage(QAction * const showGridAction, QAction * const showAlignmentAction
		,QAction * const activateGridAction, QAction * const activateAlignmentAction, QWidget *parent) :
	PreferencesPage(parent),
	mUi(new Ui::PreferencesEditorPage),
	mFontWasChanged(false),
	mFontButtonWasPressed(false),
	mWidthGrid(SettingsManager::value("GridWidth", 10).toInt()),
	mIndexGrid(SettingsManager::value("IndexGrid", 30).toInt()),
	mShowGridAction(showGridAction),
	mShowAlignmentAction(showAlignmentAction),
	mActivateGridAction(activateGridAction),
	mActivateAlignmentAction(activateAlignmentAction)
{
	mUi->setupUi(this);

	// changing grid size in QReal:Robots is forbidden
	connect(mUi->gridWidthSlider, SIGNAL(sliderMoved(int)), this, SLOT(widthGridSliderMoved(int)));
	connect(mUi->indexGridSlider, SIGNAL(sliderMoved(int)), this, SLOT(indexGridSliderMoved(int)));
	connect(mUi->fontCheckBox, SIGNAL(toggled(bool)), this, SLOT(manualFontCheckBoxChecked(bool)));
	connect(mUi->fontSelectionButton, SIGNAL(clicked()),this, SLOT(fontSelectionButtonClicked()));
	mUi->indexGridSlider->setVisible(false);
	mUi->label_20->setVisible(false);

	mUi->showGridCheckBox->setChecked(SettingsManager::value("ShowGrid", true).toBool());
	mUi->showAlignmentCheckBox->setChecked(SettingsManager::value("ShowAlignment", true).toBool());
	mUi->activateGridCheckBox->setChecked(SettingsManager::value("ActivateGrid", false).toBool());
	mUi->activateAlignmentCheckBox->setChecked(SettingsManager::value("ActivateAlignment", true).toBool());
	mUi->embeddedLinkerIndentSlider->setValue(SettingsManager::value("EmbeddedLinkerIndent", 8).toInt());
	mUi->embeddedLinkerSizeSlider->setValue(SettingsManager::value("EmbeddedLinkerSize", 6).toInt());
	mUi->zoomFactorSlider->setValue(SettingsManager::value("zoomFactor", 2).toInt());

	mUi->gridWidthSlider->setValue(mWidthGrid);
	mUi->indexGridSlider->setValue(mIndexGrid);
	mUi->fontCheckBox->setChecked(SettingsManager::value("CustomFont", false).toBool());
	mUi->fontSelectionButton->setVisible(SettingsManager::value("CustomFont", false).toBool());
}

PreferencesEditorPage::~PreferencesEditorPage()
{
	SettingsManager::setValue("GridWidth", mWidthGrid);
	SettingsManager::setValue("IndexGrid", mIndexGrid);

	delete mUi;
}

void PreferencesEditorPage::manualFontCheckBoxChecked(bool state) {
	SettingsManager::setValue("manualFontCheckBoxChecked", state);

	mFontWasChanged = !mFontWasChanged;
	mUi->fontSelectionButton->setVisible(state);
}

void PreferencesEditorPage::fontSelectionButtonClicked() {
	if (!mFontWasChanged)
		mFontWasChanged = !mFontWasChanged;
	mFontButtonWasPressed = true;
	mFontDialog = new QFontDialog();
	mFontDialog->setModal(true);
	mFontDialog->exec();
}

void PreferencesEditorPage::changeEvent(QEvent *e)
{
	switch (e->type()) {
	case QEvent::LanguageChange:
		mUi->retranslateUi(this);
		break;
	default:
		break;
	}
}

void PreferencesEditorPage::widthGridSliderMoved(int value)
{
	SettingsManager::setValue("GridWidth", value);
	emit gridChanged();
}

void PreferencesEditorPage::indexGridSliderMoved(int value)
{
	SettingsManager::setValue("IndexGrid", value);
	emit gridChanged();
}

void PreferencesEditorPage::save()
{
	SettingsManager::setValue("EmbeddedLinkerIndent", mUi->embeddedLinkerIndentSlider->value());
	SettingsManager::setValue("EmbeddedLinkerSize", mUi->embeddedLinkerSizeSlider->value());
	SettingsManager::setValue("zoomFactor", mUi->zoomFactorSlider->value());
	SettingsManager::setValue("ShowGrid", mUi->showGridCheckBox->isChecked());
	SettingsManager::setValue("ShowAlignment", mUi->showAlignmentCheckBox->isChecked());
	SettingsManager::setValue("ActivateGrid", mUi->activateGridCheckBox->isChecked());
	SettingsManager::setValue("ActivateAlignment", mUi->activateAlignmentCheckBox->isChecked());
	SettingsManager::setValue("CustomFont", mUi->fontCheckBox->isChecked());

	mWidthGrid = mUi->gridWidthSlider->value();
	mIndexGrid = mUi->indexGridSlider->value();
	SettingsManager::setValue("GridWidth", mWidthGrid);
	SettingsManager::setValue("IndexGrid", mIndexGrid);

	mShowGridAction->setChecked(mUi->showGridCheckBox->isChecked());
	mShowAlignmentAction->setChecked(mUi->showAlignmentCheckBox->isChecked());
	mActivateGridAction->setChecked(mUi->activateGridCheckBox->isChecked());
	mActivateAlignmentAction->setChecked(mUi->activateAlignmentCheckBox->isChecked());

	if (mFontWasChanged) {
		if (mFontButtonWasPressed)
			SettingsManager::setValue("CurrentFont", mFontDialog->currentFont().toString());
		QMessageBox::information(NULL, "Information", "You should restart QReal:Robots to apply changes", "ok");
		mFontWasChanged = false;
		mFontButtonWasPressed = false;
	}
}
<|endoftext|>


<commit_before>#include <unicode/strenum.h>
#include <unicode/timezone.h>
#include <unicode/ucal.h>
#include <unicode/unistr.h>

#include <Poco/Logger.h>
#include <Poco/SharedPtr.h>

#include "di/Injectable.h"
#include "l10n/IcuTimeZoneImpl.h"
#include "l10n/IcuTimeZoneProvider.h"
#include "l10n/TimeZone.h"

BEEEON_OBJECT_BEGIN(BeeeOn, IcuTimeZoneProvider)
BEEEON_OBJECT_CASTABLE(TimeZoneProvider)
BEEEON_OBJECT_END(BeeeOn, IcuTimeZoneProvider)

using namespace std;
using namespace Poco;
using namespace BeeeOn;

Nullable<BeeeOn::TimeZone> IcuTimeZoneProvider::findById(const string &id)
{
	UnicodeString uniID(id.c_str(), id.size());
	SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(uniID);

	UnicodeString tmp;
	UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	Nullable<TimeZone> zone;

	if (impl->getID(tmp) == unknownID)
		return zone;

	zone = TimeZone(new IcuTimeZoneImpl(impl));
	return zone;
}

Nullable<BeeeOn::TimeZone> IcuTimeZoneProvider::findByOffset(const Timespan &offset)
{
	Nullable<BeeeOn::TimeZone> zone;
	UErrorCode error = U_ZERO_ERROR;
	const int32_t rawOffset = offset.totalMilliseconds();

	SharedPtr<icu::StringEnumeration> e =
		icu::TimeZone::createTimeZoneIDEnumeration(
			UCAL_ZONE_TYPE_CANONICAL,
			"001", // world
			&rawOffset,
			error
		);

	if (!U_SUCCESS(error)) {
		logger().warning(u_errorName(error), __FILE__, __LINE__);
		return zone;
	}

	const UnicodeString *id;

	UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	while ((id = e->snext(error)) != NULL) {
		if (!U_SUCCESS(error)) {
			logger().warning(u_errorName(error), __FILE__, __LINE__);
			continue; // skip
		}

		SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(*id);
		UnicodeString tmp;
		if (impl->getID(tmp) == unknownID)
			continue; // skip unknown ID, should not happen here

		zone = TimeZone(new IcuTimeZoneImpl(impl));
		break;
	}

	return zone;
}

void IcuTimeZoneProvider::listTimeZones(vector<TimeZone> &zones)
{
	UErrorCode error = U_ZERO_ERROR;

	SharedPtr<icu::StringEnumeration> e =
		icu::TimeZone::createTimeZoneIDEnumeration(
			UCAL_ZONE_TYPE_CANONICAL_LOCATION,
			NULL,
			NULL,
			error
		);

	if (!U_SUCCESS(error)) {
		logger().warning(
				u_errorName(error)
				+ string(" fallback to createEnumeration()"),
				__FILE__, __LINE__);

		e = icu::TimeZone::createEnumeration();
	}

	const UnicodeString *id;

	UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	while ((id = e->snext(error)) != NULL) {
		if (!U_SUCCESS(error)) {
			logger().warning(u_errorName(error), __FILE__, __LINE__);
			continue;
		}

		SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(*id);
		UnicodeString tmp;

		if (impl->getID(tmp) == unknownID)
			continue; // skip unknown ID, should not happen here

		TimeZone zone(new IcuTimeZoneImpl(impl));
		zones.push_back(zone);
	}
}
<commit_msg>IcuTimeZoneProvider: refer to UnicodeString with prefix 'icu::'<commit_after>#include <unicode/strenum.h>
#include <unicode/timezone.h>
#include <unicode/ucal.h>
#include <unicode/unistr.h>

#include <Poco/Logger.h>
#include <Poco/SharedPtr.h>

#include "di/Injectable.h"
#include "l10n/IcuTimeZoneImpl.h"
#include "l10n/IcuTimeZoneProvider.h"
#include "l10n/TimeZone.h"

BEEEON_OBJECT_BEGIN(BeeeOn, IcuTimeZoneProvider)
BEEEON_OBJECT_CASTABLE(TimeZoneProvider)
BEEEON_OBJECT_END(BeeeOn, IcuTimeZoneProvider)

using namespace std;
using namespace Poco;
using namespace BeeeOn;

Nullable<BeeeOn::TimeZone> IcuTimeZoneProvider::findById(const string &id)
{
	icu::UnicodeString uniID(id.c_str(), id.size());
	SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(uniID);

	icu::UnicodeString tmp;
	icu::UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	Nullable<TimeZone> zone;

	if (impl->getID(tmp) == unknownID)
		return zone;

	zone = TimeZone(new IcuTimeZoneImpl(impl));
	return zone;
}

Nullable<BeeeOn::TimeZone> IcuTimeZoneProvider::findByOffset(const Timespan &offset)
{
	Nullable<BeeeOn::TimeZone> zone;
	UErrorCode error = U_ZERO_ERROR;
	const int32_t rawOffset = offset.totalMilliseconds();

	SharedPtr<icu::StringEnumeration> e =
		icu::TimeZone::createTimeZoneIDEnumeration(
			UCAL_ZONE_TYPE_CANONICAL,
			"001", // world
			&rawOffset,
			error
		);

	if (!U_SUCCESS(error)) {
		logger().warning(u_errorName(error), __FILE__, __LINE__);
		return zone;
	}

	const icu::UnicodeString *id;

	icu::UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	while ((id = e->snext(error)) != NULL) {
		if (!U_SUCCESS(error)) {
			logger().warning(u_errorName(error), __FILE__, __LINE__);
			continue; // skip
		}

		SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(*id);
		icu::UnicodeString tmp;
		if (impl->getID(tmp) == unknownID)
			continue; // skip unknown ID, should not happen here

		zone = TimeZone(new IcuTimeZoneImpl(impl));
		break;
	}

	return zone;
}

void IcuTimeZoneProvider::listTimeZones(vector<TimeZone> &zones)
{
	UErrorCode error = U_ZERO_ERROR;

	SharedPtr<icu::StringEnumeration> e =
		icu::TimeZone::createTimeZoneIDEnumeration(
			UCAL_ZONE_TYPE_CANONICAL_LOCATION,
			NULL,
			NULL,
			error
		);

	if (!U_SUCCESS(error)) {
		logger().warning(
				u_errorName(error)
				+ string(" fallback to createEnumeration()"),
				__FILE__, __LINE__);

		e = icu::TimeZone::createEnumeration();
	}

	const icu::UnicodeString *id;

	icu::UnicodeString unknownID;
	icu::TimeZone::getUnknown().getID(unknownID);

	while ((id = e->snext(error)) != NULL) {
		if (!U_SUCCESS(error)) {
			logger().warning(u_errorName(error), __FILE__, __LINE__);
			continue;
		}

		SharedPtr<icu::TimeZone> impl = icu::TimeZone::createTimeZone(*id);
		icu::UnicodeString tmp;

		if (impl->getID(tmp) == unknownID)
			continue; // skip unknown ID, should not happen here

		TimeZone zone(new IcuTimeZoneImpl(impl));
		zones.push_back(zone);
	}
}
<|endoftext|>