<commit_before>/*{{{
    Copyright © 2015 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

}}}*/
// includes {{{1
#include <array>
#include <iostream>
#include <iomanip>
#include <random>
#include "../tsc.h"
#include "spline.h"
#include "spline2.h"

// settings {{{1
constexpr int NumberOfEvaluations = 10000;
constexpr int FirstMapSize = 4;
constexpr int MaxMapSize = 1024;
constexpr int MapSize = 4;
constexpr int MinRepeat = 100;
constexpr auto StepMultiplier = 1.25;

enum DisabledTests {
    DisabledTestsBegin = -999999,
    Horizontal,
    DisabledTestsEnd
};
enum EnabledTests {
    Scalar,
    Vectorized,
    Vec2,
    Vec16,
    NBenchmarks
};

// types {{{1
typedef Spline::Point2 Point2;
typedef Spline::Point3 Point3;
typedef Spline::Point2V Point2V;
typedef Spline::Point3V Point3V;

// operator<< overloads {{{1
std::ostream &operator<<(std::ostream &s, const Point2 &xyz)
{
    using std::setw;
    return s << '[' << setw(7) << xyz[0] << ", " << setw(7) << xyz[1] << ']';
}
std::ostream &operator<<(std::ostream &s, const Point3 &xyz)
{
    using std::setw;
    return s << '[' << setw(7) << xyz[0] << ", " << setw(7) << xyz[1] << ", " << setw(7)
             << xyz[2] << ']';
}

// VectorizeBuffer {{{1
 struct VectorizeBuffer
{
    Point2V input;
    int entries = 0;
    int operator()(Point2 x)
    {
        simdize_assign(input, entries, x);
        entries = (entries + 1) % Point2V::size();
        return entries;
    }
    //VectorizeBuffer(F c) : callback(std::move(c)) {}
};

VectorizeBuffer make_vectorizer()
{
    return {};
}

// TestInfo {{{1
struct TestInfo
{
    bool enabled = false;
    int id = -1;
    TestInfo(EnabledTests t) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests, DisabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests, DisabledTests) : enabled(true), id(t) {}

    TestInfo(DisabledTests) : enabled(false) {}
    TestInfo(DisabledTests, EnabledTests t) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests) : enabled(false) {}
    TestInfo(DisabledTests, EnabledTests t, EnabledTests) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests, EnabledTests t) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests, DisabledTests) : enabled(false) {}

    TestInfo(DisabledTests, EnabledTests t, DisabledTests) : enabled(true), id(t) {}

    operator bool() const { return enabled; }
    operator int() const { return id; }
    operator long() const { return id; }
};
// Runner Lambda {{{1
struct Runner
{
    // data members{{{2
    const int Repetitions = MinRepeat;
    const int MapSize;
    TimeStampCounter tsc;
    double mean[NBenchmarks] = {};
    double stddev[NBenchmarks] = {};

    // Runner::Runner{{{2
    Runner(int R, int S) : Repetitions(R), MapSize(S) {}

    void recordTsc(int Test, double norm)  //{{{2
    {
        const double x = tsc.cycles() / norm;
        mean[Test] += x;
        stddev[Test] += x * x;
    }
    template <typename I, typename J> void printRatio(I i, J j)  //{{{2
    {
        if (TestInfo(i) && TestInfo(j)) {
            const auto ratio = mean[i] / mean[j];
            std::cout << std::setprecision(3) << std::setw(9) << ratio;
            std::cout << std::setprecision(3) << std::setw(9)
                      << ratio * std::sqrt(stddev[i] * stddev[i] / (mean[i] * mean[i]) +
                                           stddev[j] * stddev[j] / (mean[j] * mean[j]));
        }
    }
    // benchmarkSearch{{{2
    template <typename F> void benchmark(const TestInfo Test, F &&fun, double err = 20)
    {
        if (Test) {
            do {
                mean[Test] = 0;
                stddev[Test] = 0;

                fun(); // one cache warm-up run to remove one outlier
                for (auto rep = Repetitions; rep; --rep) {
                    tsc.start();
                    fun();
                    tsc.stop();
                    recordTsc(Test, NumberOfEvaluations);
                }

                mean[Test] /= Repetitions;
                stddev[Test] /= Repetitions;
                stddev[Test] = std::sqrt(stddev[Test] - mean[Test] * mean[Test]);
            } while (stddev[Test] * err > mean[Test]);
            std::cout << std::setw(9) << std::setprecision(3) << mean[Test];
            std::cout << std::setw(9) << std::setprecision(3) << stddev[Test];
            std::cout << std::flush;
        }
    }
    //}}}2
};
int main()  // {{{1
{
    // output header {{{2
    using std::cout;
    using std::setw;
    using std::setprecision;
    cout << "NumberOfEvaluations: " << NumberOfEvaluations << '\n';
    cout << "MinRepeat: " << MinRepeat << '\n';
    cout << setw(8) << "MapSize";
    if (TestInfo(Scalar)) {
        cout << setw(18) << "Scalar";
    }
    if (TestInfo(Vectorized)) {
        cout << setw(18) << "Vectorized";
    }
    if (TestInfo(Vec16)) {
        cout << setw(18) << "Vec16";
    }
    if (TestInfo(Vec2)) {
        cout << setw(18) << "Vec2";
    }
    if (TestInfo(Horizontal)) {
        cout << setw(18) << "Horizontal";
    }
    if (TestInfo(Scalar) && TestInfo(Vectorized)) {
        cout << setw(18) << "Scalar/Vectorized";
    }
    if (TestInfo(Scalar) && TestInfo(Vec16)) {
        cout << setw(18) << "Scalar/Vec16";
    }
    if (TestInfo(Scalar) && TestInfo(Vec2)) {
        cout << setw(18) << "Scalar/Vec2";
    }
    if (TestInfo(Scalar) && TestInfo(Horizontal)) {
        cout << setw(18) << "Scalar/Horizontal";
    }
    cout << std::endl;

    // random number generator {{{2
    std::default_random_engine randomEngine(1);
    std::uniform_real_distribution<float> uniform(-1.f, 1.f);

    // random search points {{{2
    std::vector<Point2> searchPoints;
    searchPoints.reserve(NumberOfEvaluations);
    for (int i = 0; i < NumberOfEvaluations; ++i) {
        searchPoints.emplace_back(Point2{uniform(randomEngine), uniform(randomEngine)});
    }

    // MapSize loop {{{2
    //for (int MapSize = FirstMapSize; MapSize <= MaxMapSize; MapSize *= StepMultiplier) {
        // initialize map with random values {{{2
        Spline spline(-1.f, 1.f, MapSize, -1.f, 1.f, MapSize);
        Spline2<MapSize, MapSize> spline2(-1.f, 1.f, -1.f, 1.f);
        for (int i = 0; i < spline.GetNPoints(); ++i) {
            const float xyz[3] = {uniform(randomEngine), uniform(randomEngine),
                                  uniform(randomEngine)};
            spline.Fill(i, xyz);
            spline2.Fill(i, xyz);
        }

        Runner runner(MinRepeat, MapSize);
        cout << setw(8) << spline.GetMapSize() << std::flush;

        // Scalar {{{2
        runner.benchmark(Scalar, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValueScalar(p);
                asm("" ::"m"(p2));
            }
        });

        // Vectorized {{{2
        runner.benchmark(Vectorized, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValue(p);
                asm("" ::"m"(p2));
            }
        });

        // Vec16 {{{2
        runner.benchmark(Vec16, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValue16(p);
                asm("" ::"m"(p2));
            }
        });

        // Vec2 {{{2
        runner.benchmark(Vec2, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline2.GetValue(p);
                asm("" ::"m"(p2));
            }
        });

        // Horizontal {{{2
        runner.benchmark(Horizontal, [&] {
            auto vectorizer = make_vectorizer();
            for (const auto &p : searchPoints) {
                if (0 == vectorizer(p)) {
                    const auto &p2 = spline.GetValue(vectorizer.input);
                    asm("" ::"m"(p2));
                }
            }
        });

        // print search timings {{{2
        runner.printRatio(Scalar, Vectorized);
        runner.printRatio(Scalar, Vec2);
        runner.printRatio(Scalar, Horizontal);
        cout << std::flush;

        // verify equivalence {{{2
        if (TestInfo(Scalar)) {
            bool failed = false;
            for (const auto &p : searchPoints) {
                const auto &ps = spline.GetValueScalar(p);
                if (TestInfo(Vectorized)) {  //{{{3
                    const auto &pv = spline.GetValue(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVectorized not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
                if (TestInfo(Vec16)) {  //{{{3
                    const auto &pv = spline.GetValue16(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVec16 not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
                if (TestInfo(Vec2)) {  //{{{3
                    const auto &pv = spline2.GetValue(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVec2 not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
            }
            if (failed) {
                //std::cout << '\n' << spline. << '\n';
                return 1;
            } else {
                cout << " ✓";
            }
        }
        cout << std::endl;
    //}
    return 0;
}  // }}}1

// vim: foldmethod=marker
<commit_msg>spline: verify Horizontal<commit_after>/*{{{
    Copyright © 2015 Matthias Kretz <kretz@kde.org>

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

}}}*/
// includes {{{1
#include <array>
#include <iostream>
#include <iomanip>
#include <random>
#include "../tsc.h"
#include "spline.h"
#include "spline2.h"

// settings {{{1
constexpr int NumberOfEvaluations = 10000;
constexpr int FirstMapSize = 4;
constexpr int MaxMapSize = 1024;
constexpr int MapSize = 4;
constexpr int MinRepeat = 100;
constexpr auto StepMultiplier = 1.25;

enum DisabledTests {
    DisabledTestsBegin = -999999,
    Horizontal,
    DisabledTestsEnd
};
enum EnabledTests {
    Scalar,
    Vectorized,
    Vec2,
    Vec16,
    NBenchmarks
};

// types {{{1
typedef Spline::Point2 Point2;
typedef Spline::Point3 Point3;
typedef Spline::Point2V Point2V;
typedef Spline::Point3V Point3V;

// operator<< overloads {{{1
std::ostream &operator<<(std::ostream &s, const Point2 &xyz)
{
    using std::setw;
    return s << '[' << setw(7) << xyz[0] << ", " << setw(7) << xyz[1] << ']';
}
std::ostream &operator<<(std::ostream &s, const Point3 &xyz)
{
    using std::setw;
    return s << '[' << setw(7) << xyz[0] << ", " << setw(7) << xyz[1] << ", " << setw(7)
             << xyz[2] << ']';
}

// VectorizeBuffer {{{1
template <typename Input> struct VectorizeBuffer
{
    typedef simdize<Input> InputV;
    InputV input;
    int entries = 0;
    int operator()(Input x)
    {
        simdize_assign(input, entries, x);
        entries = (entries + 1) % InputV::size();
        return entries;
    }
};

// TestInfo {{{1
struct TestInfo
{
    bool enabled = false;
    int id = -1;
    TestInfo(EnabledTests t) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, EnabledTests, DisabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests, EnabledTests) : enabled(true), id(t) {}
    TestInfo(EnabledTests t, DisabledTests, DisabledTests) : enabled(true), id(t) {}

    TestInfo(DisabledTests) : enabled(false) {}
    TestInfo(DisabledTests, EnabledTests t) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests) : enabled(false) {}
    TestInfo(DisabledTests, EnabledTests t, EnabledTests) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests, EnabledTests t) : enabled(true), id(t) {}
    TestInfo(DisabledTests, DisabledTests, DisabledTests) : enabled(false) {}

    TestInfo(DisabledTests, EnabledTests t, DisabledTests) : enabled(true), id(t) {}

    operator bool() const { return enabled; }
    operator int() const { return id; }
    operator long() const { return id; }
};
// Runner Lambda {{{1
struct Runner
{
    // data members{{{2
    const int Repetitions = MinRepeat;
    const int MapSize;
    TimeStampCounter tsc;
    double mean[NBenchmarks] = {};
    double stddev[NBenchmarks] = {};

    // Runner::Runner{{{2
    Runner(int R, int S) : Repetitions(R), MapSize(S) {}

    void recordTsc(int Test, double norm)  //{{{2
    {
        const double x = tsc.cycles() / norm;
        mean[Test] += x;
        stddev[Test] += x * x;
    }
    template <typename I, typename J> void printRatio(I i, J j)  //{{{2
    {
        if (TestInfo(i) && TestInfo(j)) {
            const auto ratio = mean[i] / mean[j];
            std::cout << std::setprecision(3) << std::setw(9) << ratio;
            std::cout << std::setprecision(3) << std::setw(9)
                      << ratio * std::sqrt(stddev[i] * stddev[i] / (mean[i] * mean[i]) +
                                           stddev[j] * stddev[j] / (mean[j] * mean[j]));
        }
    }
    // benchmarkSearch{{{2
    template <typename F> void benchmark(const TestInfo Test, F &&fun, double err = 20)
    {
        if (Test) {
            do {
                mean[Test] = 0;
                stddev[Test] = 0;

                fun(); // one cache warm-up run to remove one outlier
                for (auto rep = Repetitions; rep; --rep) {
                    tsc.start();
                    fun();
                    tsc.stop();
                    recordTsc(Test, NumberOfEvaluations);
                }

                mean[Test] /= Repetitions;
                stddev[Test] /= Repetitions;
                stddev[Test] = std::sqrt(stddev[Test] - mean[Test] * mean[Test]);
            } while (stddev[Test] * err > mean[Test]);
            std::cout << std::setw(9) << std::setprecision(3) << mean[Test];
            std::cout << std::setw(9) << std::setprecision(3) << stddev[Test];
            std::cout << std::flush;
        }
    }
    //}}}2
};
int main()  // {{{1
{
    // output header {{{2
    using std::cout;
    using std::setw;
    using std::setprecision;
    cout << "NumberOfEvaluations: " << NumberOfEvaluations << '\n';
    cout << "MinRepeat: " << MinRepeat << '\n';
    cout << setw(8) << "MapSize";
    if (TestInfo(Scalar)) {
        cout << setw(18) << "Scalar";
    }
    if (TestInfo(Vectorized)) {
        cout << setw(18) << "Vectorized";
    }
    if (TestInfo(Vec16)) {
        cout << setw(18) << "Vec16";
    }
    if (TestInfo(Vec2)) {
        cout << setw(18) << "Vec2";
    }
    if (TestInfo(Horizontal)) {
        cout << setw(18) << "Horizontal";
    }
    if (TestInfo(Scalar) && TestInfo(Vectorized)) {
        cout << setw(18) << "Scalar/Vectorized";
    }
    if (TestInfo(Scalar) && TestInfo(Vec16)) {
        cout << setw(18) << "Scalar/Vec16";
    }
    if (TestInfo(Scalar) && TestInfo(Vec2)) {
        cout << setw(18) << "Scalar/Vec2";
    }
    if (TestInfo(Scalar) && TestInfo(Horizontal)) {
        cout << setw(18) << "Scalar/Horizontal";
    }
    cout << std::endl;

    // random number generator {{{2
    std::default_random_engine randomEngine(1);
    std::uniform_real_distribution<float> uniform(-1.f, 1.f);

    // random search points {{{2
    std::vector<Point2> searchPoints;
    searchPoints.reserve(NumberOfEvaluations);
    for (int i = 0; i < NumberOfEvaluations; ++i) {
        searchPoints.emplace_back(Point2{uniform(randomEngine), uniform(randomEngine)});
    }

    // MapSize loop {{{2
    //for (int MapSize = FirstMapSize; MapSize <= MaxMapSize; MapSize *= StepMultiplier) {
        // initialize map with random values {{{2
        Spline spline(-1.f, 1.f, MapSize, -1.f, 1.f, MapSize);
        Spline2<MapSize, MapSize> spline2(-1.f, 1.f, -1.f, 1.f);
        for (int i = 0; i < spline.GetNPoints(); ++i) {
            const float xyz[3] = {uniform(randomEngine), uniform(randomEngine),
                                  uniform(randomEngine)};
            spline.Fill(i, xyz);
            spline2.Fill(i, xyz);
        }

        Runner runner(MinRepeat, MapSize);
        cout << setw(8) << spline.GetMapSize() << std::flush;

        // Scalar {{{2
        runner.benchmark(Scalar, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValueScalar(p);
                asm("" ::"m"(p2));
            }
        });

        // Vectorized {{{2
        runner.benchmark(Vectorized, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValue(p);
                asm("" ::"m"(p2));
            }
        });

        // Vec16 {{{2
        runner.benchmark(Vec16, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline.GetValue16(p);
                asm("" ::"m"(p2));
            }
        });

        // Vec2 {{{2
        runner.benchmark(Vec2, [&] {
            for (const auto &p : searchPoints) {
                const auto &p2 = spline2.GetValue(p);
                asm("" ::"m"(p2));
            }
        });

        // Horizontal {{{2
        runner.benchmark(Horizontal, [&] {
            VectorizeBuffer<Point2> vectorizer;
            for (const auto &p : searchPoints) {
                if (0 == vectorizer(p)) {
                    const auto &p2 = spline.GetValue(vectorizer.input);
                    asm("" ::"m"(p2));
                }
            }
        });

        // print search timings {{{2
        runner.printRatio(Scalar, Vectorized);
        runner.printRatio(Scalar, Vec2);
        runner.printRatio(Scalar, Horizontal);
        cout << std::flush;

        // verify equivalence {{{2
        if (TestInfo(Scalar)) {
            bool failed = false;
            VectorizeBuffer<Point2> vectorizer2;
            VectorizeBuffer<Point3> vectorizer3;
            for (const auto &p : searchPoints) {
                const auto &ps = spline.GetValueScalar(p);
                if (TestInfo(Vectorized)) {  //{{{3
                    const auto &pv = spline.GetValue(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVectorized not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
                if (TestInfo(Vec16)) {  //{{{3
                    const auto &pv = spline.GetValue16(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVec16 not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
                if (TestInfo(Vec2)) {  //{{{3
                    const auto &pv = spline2.GetValue(p);
                    for (int i = 0; i < 3; ++i) {
                        if (std::abs(ps[i] - pv[i]) > 0.00001f) {
                            std::cout << "\nVec2 not equal at " << p << ": " << ps
                                      << " vs. " << pv;
                            failed = true;
                            break;
                        }
                    }
                }
                vectorizer3(ps);
                if (0 == vectorizer2(p)) {
                    if (TestInfo(Horizontal)) {  //{{{3
                        const auto &pv = spline.GetValue(vectorizer2.input);
                        for (int i = 0; i < 3; ++i) {
                            if (any_of(abs(vectorizer3.input[i] - pv[i]) > 0.00001f)) {
                                cout << "\nHorizontal not equal at " << vectorizer2.input
                                     << ": " << vectorizer3.input << " vs. " << pv;
                                failed = true;
                                break;
                            }
                        }
                    }
                }
            }
            if (failed) {
                //std::cout << '\n' << spline. << '\n';
                return 1;
            } else {
                cout << " ✓";
            }
        }
        cout << std::endl;
    //}
    return 0;
}  // }}}1

// vim: foldmethod=marker
<|endoftext|>


<commit_before>//- ------------------------------------------------------------------
//-    Copyright (c) Yasuhiro SHIMIZU -- All Rights Reserved
//- ------------------------------------------------------------------

#include "MockIO.h"

namespace IO {

IO *gMockIoPtr = nullptr;

} // namespace IO

void IO_Write(IoAddress addr, IoData value)
{
    // mock_c()->actualCall("IO_Write")
    //         ->withIntParameters("addr", addr)
    //         ->withIntParameters("value", value);
}

IoData IO_Read(IoAddress addr)
{
   //  mock_c()->actualCall("IO_Read")
   //          ->withIntParameters("addr", addr);
   //
   // return mock_c()->returnValue().value.intValue;
   return 0U;
}
<commit_msg>implement mock-c-wrappers.<commit_after>//- ------------------------------------------------------------------
//-    Copyright (c) Yasuhiro SHIMIZU -- All Rights Reserved
//- ------------------------------------------------------------------

#include "MockIO.h"

namespace IO {

IO *gMockIoPtr = nullptr;

} // namespace IO

void IO_Write(IoAddress addr, IoData value)
{
    IO::gMockIoPtr->Write(addr, value);
}

IoData IO_Read(IoAddress addr)
{
   return IO::gMockIoPtr->Read(addr);
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2013 The Communi Project
*
* 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.
*/

#include "ircchannel.h"
#include "ircchannel_p.h"
#include "ircusermodel.h"
#include "ircusermodel_p.h"
#include "ircbuffermodel.h"
#include "ircbuffermodel_p.h"
#include "irccommand.h"
#include "ircconnection.h"
#include "ircuser_p.h"
#include "irc.h"

IRC_BEGIN_NAMESPACE

/*!
    \file ircchannel.h
    \brief \#include <IrcChannel>
 */

/*!
    \class IrcChannel ircchannel.h <IrcChannel>
    \ingroup models
    \brief Keeps track of channel status.

    \sa IrcBufferModel
*/

#ifndef IRC_DOXYGEN
static QString getPrefix(const QString& name, const QStringList& prefixes)
{
    int i = 0;
    while (i < name.length() && prefixes.contains(name.at(i)))
        ++i;
    return name.left(i);
}

static QString channelName(const QString& title, const QStringList& prefixes)
{
    int i = 0;
    while (i < title.length() && prefixes.contains(title.at(i)))
        ++i;
    return title.mid(i);
}

static QString userName(const QString& name, const QStringList& prefixes)
{
    QString copy = name;
    while (!copy.isEmpty() && prefixes.contains(copy.at(0)))
        copy.remove(0, 1);
    return Irc::nickFromPrefix(copy);
}

IrcChannelPrivate::IrcChannelPrivate() : joined(0), left(0)
{
}

IrcChannelPrivate::~IrcChannelPrivate()
{
}

void IrcChannelPrivate::init(const QString& title, IrcBufferModel* m)
{
    IrcBufferPrivate::init(title, m);

    const QStringList chanTypes = m->network()->channelTypes();
    prefix = getPrefix(title, chanTypes);
    name = channelName(title, chanTypes);
}

void IrcChannelPrivate::changeMode(const QString& value)
{
    QString copy = mode;
    bool add = true;
    for (int i = 0; i < value.size(); ++i) {
        QChar c = value.at(i);
        if (c == QLatin1Char('+')) {
            add = true;
        } else if (c == QLatin1Char('-')) {
            add = false;
        } else {
            if (add) {
                if (!copy.contains(c))
                    copy += c;
            } else {
                copy.remove(c);
            }
        }
    }
    setMode(copy);
}

void IrcChannelPrivate::setMode(const QString& value)
{
    Q_Q(IrcChannel);
    if (mode != value) {
        mode = value;
        emit q->modeChanged(mode);
    }
}

void IrcChannelPrivate::setTopic(const QString& value)
{
    Q_Q(IrcChannel);
    if (topic != value) {
        topic = value;
        emit q->topicChanged(topic);
    }
}

void IrcChannelPrivate::addUser(const QString& name)
{
    Q_Q(IrcChannel);
    const QStringList prefixes = q->network()->prefixes();

    IrcUser* user = new IrcUser(q);
    IrcUserPrivate* priv = IrcUserPrivate::get(user);
    priv->channel = q;
    priv->setName(userName(name, prefixes));
    priv->setPrefix(getPrefix(name, prefixes));
    priv->setMode(q->network()->prefixToMode(user->prefix()));
    activeUsers.prepend(user);
    userList.append(user);
    userMap.insert(user->name(), user);

    foreach (IrcUserModel* model, userModels)
        IrcUserModelPrivate::get(model)->addUser(user);
}

bool IrcChannelPrivate::removeUser(const QString& name)
{
    if (IrcUser* user = userMap.value(name)) {
        userMap.remove(name);
        userList.removeOne(user);
        activeUsers.removeOne(user);
        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->removeUser(user);
        user->deleteLater();
        return true;
    }
    return false;
}

void IrcChannelPrivate::setUsers(const QStringList& names)
{
    Q_Q(IrcChannel);
    const QStringList prefixes = q->network()->prefixes();

    qDeleteAll(userList);
    userMap.clear();
    userList.clear();
    activeUsers.clear();

    QList<IrcUser*> users;
    foreach (const QString& name, names) {
        IrcUser* user = new IrcUser(q);
        IrcUserPrivate* priv = IrcUserPrivate::get(user);
        priv->channel = q;
        priv->setName(userName(name, prefixes));
        priv->setPrefix(getPrefix(name, prefixes));
        priv->setMode(q->network()->prefixToMode(user->prefix()));
        activeUsers.append(user);
        userList.append(user);
        userMap.insert(user->name(), user);
        users.append(user);
    }

    foreach (IrcUserModel* model, userModels)
        IrcUserModelPrivate::get(model)->setUsers(users);
}

bool IrcChannelPrivate::renameUser(const QString& from, const QString& to)
{
    if (IrcUser* user = userMap.take(from)) {
        IrcUserPrivate::get(user)->setName(to);
        userMap.insert(to, user);

        QStringList names = userMap.keys();
        foreach (IrcUserModel* model, userModels) {
            IrcUserModelPrivate::get(model)->renameUser(user);
            emit model->namesChanged(names);
        }
        return true;
    }
    return false;
}

void IrcChannelPrivate::setUserMode(const QString& name, const QString& command)
{
    if (IrcUser* user = userMap.value(name)) {
        bool add = true;
        QString mode = user->mode();
        QString prefix = user->prefix();
        const IrcNetwork* network = model->network();
        for (int i = 0; i < command.size(); ++i) {
            QChar c = command.at(i);
            if (c == QLatin1Char('+')) {
                add = true;
            } else if (c == QLatin1Char('-')) {
                add = false;
            } else {
                QString p = network->modeToPrefix(c);
                if (add) {
                    if (!mode.contains(c))
                        mode += c;
                    if (!prefix.contains(p))
                        prefix += p;
                } else {
                    mode.remove(c);
                    prefix.remove(p);
                }
            }
        }

        IrcUserPrivate* priv = IrcUserPrivate::get(user);
        priv->setPrefix(prefix);
        priv->setMode(mode);

        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->setUserMode(user);
    }
}

void IrcChannelPrivate::promoteUser(const QString& name)
{
    if (IrcUser* user = userMap.value(name)) {
        const int idx = activeUsers.indexOf(user);
        Q_ASSERT(idx != -1);
        activeUsers.move(idx, 0);
        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->promoteUser(user);
    }
}

bool IrcChannelPrivate::processJoinMessage(IrcJoinMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        ++joined;
        emitActiveChanged();
    } else {
        addUser(message->nick());
    }
    return true;
}

bool IrcChannelPrivate::processKickMessage(IrcKickMessage* message)
{
    if (!message->user().compare(message->connection()->nickName(), Qt::CaseInsensitive)) {
        ++left;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->user());
}

bool IrcChannelPrivate::processModeMessage(IrcModeMessage* message)
{
    if (message->kind() == IrcModeMessage::Channel) {
        if (message->isReply())
            setMode(message->mode());
        else
            changeMode(message->mode());
        return true;
    } else if (!message->argument().isEmpty()) {
        setUserMode(message->argument(), message->mode());
    }
    return true;
}

bool IrcChannelPrivate::processNamesMessage(IrcNamesMessage* message)
{
    setUsers(message->names());
    return true;
}

bool IrcChannelPrivate::processNickMessage(IrcNickMessage* message)
{
    const bool renamed = renameUser(message->oldNick(), message->newNick());
    if (renamed)
        promoteUser(message->newNick());
    return renamed;
}

bool IrcChannelPrivate::processNoticeMessage(IrcNoticeMessage* message)
{
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processNumericMessage(IrcNumericMessage* message)
{
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processPartMessage(IrcPartMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        ++left;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->nick());
}

bool IrcChannelPrivate::processPrivateMessage(IrcPrivateMessage* message)
{
    const QString content = message->content();
    const bool prefixed = !content.isEmpty() && message->network()->prefixes().contains(content.at(0));
    foreach (IrcUser* user, activeUsers) {
        const QString str = prefixed ? user->title() : user->name();
        if (content.startsWith(str)) {
            promoteUser(user->name());
            break;
        }
    }
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processQuitMessage(IrcQuitMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        joined = 0;
        left = 0;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->nick()) || IrcBufferPrivate::processQuitMessage(message);
}

bool IrcChannelPrivate::processTopicMessage(IrcTopicMessage* message)
{
    setTopic(message->topic());
    return true;
}
#endif // IRC_DOXYGEN

/*!
    Constructs a new channel object with \a parent.
 */
IrcChannel::IrcChannel(QObject* parent)
    : IrcBuffer(*new IrcChannelPrivate, parent)
{
}

/*!
    Destructs the channel object.
 */
IrcChannel::~IrcChannel()
{
    Q_D(IrcChannel);
    qDeleteAll(d->userList);
    d->userList.clear();
    d->userMap.clear();
    d->userModels.clear();
    emit destroyed(this);
}

/*!
    This property holds the channel mode.

    \par Access function:
    \li QString mode() const

    \par Notifier signal:
    \li void modeChanged(const QString& mode)
 */
QString IrcChannel::mode() const
{
    Q_D(const IrcChannel);
    return d->mode;
}

/*!
    This property holds the channel topic.

    \par Access function:
    \li QString topic() const

    \par Notifier signal:
    \li void topicChanged(const QString& topic)
 */
QString IrcChannel::topic() const
{
    Q_D(const IrcChannel);
    return d->topic;
}

bool IrcChannel::isActive() const
{
    Q_D(const IrcChannel);
    return IrcBuffer::isActive() && d->joined > d->left;
}

/*!
    Parts the channel with an optional \a reason.

    This method is provided for convenience. It is equal to:
    \code
    IrcCommand* command = IrcCommand::createPart(channel->title(), reason);
    channel->sendCommand(command);
    \endcode

    \sa IrcBuffer::sendCommand(), IrcCommand::createPart()
 */
void IrcChannel::part(const QString& reason)
{
    sendCommand(IrcCommand::createPart(title(), reason));
}

#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const IrcChannel* channel)
{
    if (!channel)
        return debug << "IrcChannel(0x0) ";
    debug.nospace() << channel->metaObject()->className() << '(' << (void*) channel;
    if (!channel->objectName().isEmpty())
        debug.nospace() << ", name=" << qPrintable(channel->objectName());
    if (!channel->title().isEmpty())
        debug.nospace() << ", title=" << qPrintable(channel->title());
    debug.nospace() << ')';
    return debug.space();
}
#endif // QT_NO_DEBUG_STREAM

#include "moc_ircchannel.cpp"

IRC_END_NAMESPACE
<commit_msg>Sort IrcUser mode & prefix as appropriate<commit_after>/*
* Copyright (C) 2008-2013 The Communi Project
*
* 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.
*/

#include "ircchannel.h"
#include "ircchannel_p.h"
#include "ircusermodel.h"
#include "ircusermodel_p.h"
#include "ircbuffermodel.h"
#include "ircbuffermodel_p.h"
#include "irccommand.h"
#include "ircconnection.h"
#include "ircuser_p.h"
#include "irc.h"

IRC_BEGIN_NAMESPACE

/*!
    \file ircchannel.h
    \brief \#include <IrcChannel>
 */

/*!
    \class IrcChannel ircchannel.h <IrcChannel>
    \ingroup models
    \brief Keeps track of channel status.

    \sa IrcBufferModel
*/

#ifndef IRC_DOXYGEN
static QString getPrefix(const QString& name, const QStringList& prefixes)
{
    int i = 0;
    while (i < name.length() && prefixes.contains(name.at(i)))
        ++i;
    return name.left(i);
}

static QString channelName(const QString& title, const QStringList& prefixes)
{
    int i = 0;
    while (i < title.length() && prefixes.contains(title.at(i)))
        ++i;
    return title.mid(i);
}

static QString userName(const QString& name, const QStringList& prefixes)
{
    QString copy = name;
    while (!copy.isEmpty() && prefixes.contains(copy.at(0)))
        copy.remove(0, 1);
    return Irc::nickFromPrefix(copy);
}

IrcChannelPrivate::IrcChannelPrivate() : joined(0), left(0)
{
}

IrcChannelPrivate::~IrcChannelPrivate()
{
}

void IrcChannelPrivate::init(const QString& title, IrcBufferModel* m)
{
    IrcBufferPrivate::init(title, m);

    const QStringList chanTypes = m->network()->channelTypes();
    prefix = getPrefix(title, chanTypes);
    name = channelName(title, chanTypes);
}

void IrcChannelPrivate::changeMode(const QString& value)
{
    QString copy = mode;
    bool add = true;
    for (int i = 0; i < value.size(); ++i) {
        QChar c = value.at(i);
        if (c == QLatin1Char('+')) {
            add = true;
        } else if (c == QLatin1Char('-')) {
            add = false;
        } else {
            if (add) {
                if (!copy.contains(c))
                    copy += c;
            } else {
                copy.remove(c);
            }
        }
    }
    setMode(copy);
}

void IrcChannelPrivate::setMode(const QString& value)
{
    Q_Q(IrcChannel);
    if (mode != value) {
        mode = value;
        emit q->modeChanged(mode);
    }
}

void IrcChannelPrivate::setTopic(const QString& value)
{
    Q_Q(IrcChannel);
    if (topic != value) {
        topic = value;
        emit q->topicChanged(topic);
    }
}

void IrcChannelPrivate::addUser(const QString& name)
{
    Q_Q(IrcChannel);
    const QStringList prefixes = q->network()->prefixes();

    IrcUser* user = new IrcUser(q);
    IrcUserPrivate* priv = IrcUserPrivate::get(user);
    priv->channel = q;
    priv->setName(userName(name, prefixes));
    priv->setPrefix(getPrefix(name, prefixes));
    priv->setMode(q->network()->prefixToMode(user->prefix()));
    activeUsers.prepend(user);
    userList.append(user);
    userMap.insert(user->name(), user);

    foreach (IrcUserModel* model, userModels)
        IrcUserModelPrivate::get(model)->addUser(user);
}

bool IrcChannelPrivate::removeUser(const QString& name)
{
    if (IrcUser* user = userMap.value(name)) {
        userMap.remove(name);
        userList.removeOne(user);
        activeUsers.removeOne(user);
        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->removeUser(user);
        user->deleteLater();
        return true;
    }
    return false;
}

void IrcChannelPrivate::setUsers(const QStringList& names)
{
    Q_Q(IrcChannel);
    const QStringList prefixes = q->network()->prefixes();

    qDeleteAll(userList);
    userMap.clear();
    userList.clear();
    activeUsers.clear();

    QList<IrcUser*> users;
    foreach (const QString& name, names) {
        IrcUser* user = new IrcUser(q);
        IrcUserPrivate* priv = IrcUserPrivate::get(user);
        priv->channel = q;
        priv->setName(userName(name, prefixes));
        priv->setPrefix(getPrefix(name, prefixes));
        priv->setMode(q->network()->prefixToMode(user->prefix()));
        activeUsers.append(user);
        userList.append(user);
        userMap.insert(user->name(), user);
        users.append(user);
    }

    foreach (IrcUserModel* model, userModels)
        IrcUserModelPrivate::get(model)->setUsers(users);
}

bool IrcChannelPrivate::renameUser(const QString& from, const QString& to)
{
    if (IrcUser* user = userMap.take(from)) {
        IrcUserPrivate::get(user)->setName(to);
        userMap.insert(to, user);

        QStringList names = userMap.keys();
        foreach (IrcUserModel* model, userModels) {
            IrcUserModelPrivate::get(model)->renameUser(user);
            emit model->namesChanged(names);
        }
        return true;
    }
    return false;
}

void IrcChannelPrivate::setUserMode(const QString& name, const QString& command)
{
    if (IrcUser* user = userMap.value(name)) {
        bool add = true;
        QString mode = user->mode();
        QString prefix = user->prefix();
        const IrcNetwork* network = model->network();
        for (int i = 0; i < command.size(); ++i) {
            QChar c = command.at(i);
            if (c == QLatin1Char('+')) {
                add = true;
            } else if (c == QLatin1Char('-')) {
                add = false;
            } else {
                QString p = network->modeToPrefix(c);
                if (add) {
                    if (!mode.contains(c))
                        mode += c;
                    if (!prefix.contains(p))
                        prefix += p;
                } else {
                    mode.remove(c);
                    prefix.remove(p);
                }
            }
        }

        QString sortedMode;
        foreach (const QString& m, network->modes())
            if (mode.contains(m))
                sortedMode += m;

        QString sortedPrefix;
        foreach (const QString& p, network->prefixes())
            if (prefix.contains(p))
                sortedPrefix += p;

        IrcUserPrivate* priv = IrcUserPrivate::get(user);
        priv->setPrefix(sortedPrefix);
        priv->setMode(sortedMode);

        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->setUserMode(user);
    }
}

void IrcChannelPrivate::promoteUser(const QString& name)
{
    if (IrcUser* user = userMap.value(name)) {
        const int idx = activeUsers.indexOf(user);
        Q_ASSERT(idx != -1);
        activeUsers.move(idx, 0);
        foreach (IrcUserModel* model, userModels)
            IrcUserModelPrivate::get(model)->promoteUser(user);
    }
}

bool IrcChannelPrivate::processJoinMessage(IrcJoinMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        ++joined;
        emitActiveChanged();
    } else {
        addUser(message->nick());
    }
    return true;
}

bool IrcChannelPrivate::processKickMessage(IrcKickMessage* message)
{
    if (!message->user().compare(message->connection()->nickName(), Qt::CaseInsensitive)) {
        ++left;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->user());
}

bool IrcChannelPrivate::processModeMessage(IrcModeMessage* message)
{
    if (message->kind() == IrcModeMessage::Channel) {
        if (message->isReply())
            setMode(message->mode());
        else
            changeMode(message->mode());
        return true;
    } else if (!message->argument().isEmpty()) {
        setUserMode(message->argument(), message->mode());
    }
    return true;
}

bool IrcChannelPrivate::processNamesMessage(IrcNamesMessage* message)
{
    setUsers(message->names());
    return true;
}

bool IrcChannelPrivate::processNickMessage(IrcNickMessage* message)
{
    const bool renamed = renameUser(message->oldNick(), message->newNick());
    if (renamed)
        promoteUser(message->newNick());
    return renamed;
}

bool IrcChannelPrivate::processNoticeMessage(IrcNoticeMessage* message)
{
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processNumericMessage(IrcNumericMessage* message)
{
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processPartMessage(IrcPartMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        ++left;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->nick());
}

bool IrcChannelPrivate::processPrivateMessage(IrcPrivateMessage* message)
{
    const QString content = message->content();
    const bool prefixed = !content.isEmpty() && message->network()->prefixes().contains(content.at(0));
    foreach (IrcUser* user, activeUsers) {
        const QString str = prefixed ? user->title() : user->name();
        if (content.startsWith(str)) {
            promoteUser(user->name());
            break;
        }
    }
    promoteUser(message->nick());
    return true;
}

bool IrcChannelPrivate::processQuitMessage(IrcQuitMessage* message)
{
    if (message->flags() & IrcMessage::Own) {
        joined = 0;
        left = 0;
        emitActiveChanged();
        return true;
    }
    return removeUser(message->nick()) || IrcBufferPrivate::processQuitMessage(message);
}

bool IrcChannelPrivate::processTopicMessage(IrcTopicMessage* message)
{
    setTopic(message->topic());
    return true;
}
#endif // IRC_DOXYGEN

/*!
    Constructs a new channel object with \a parent.
 */
IrcChannel::IrcChannel(QObject* parent)
    : IrcBuffer(*new IrcChannelPrivate, parent)
{
}

/*!
    Destructs the channel object.
 */
IrcChannel::~IrcChannel()
{
    Q_D(IrcChannel);
    qDeleteAll(d->userList);
    d->userList.clear();
    d->userMap.clear();
    d->userModels.clear();
    emit destroyed(this);
}

/*!
    This property holds the channel mode.

    \par Access function:
    \li QString mode() const

    \par Notifier signal:
    \li void modeChanged(const QString& mode)
 */
QString IrcChannel::mode() const
{
    Q_D(const IrcChannel);
    return d->mode;
}

/*!
    This property holds the channel topic.

    \par Access function:
    \li QString topic() const

    \par Notifier signal:
    \li void topicChanged(const QString& topic)
 */
QString IrcChannel::topic() const
{
    Q_D(const IrcChannel);
    return d->topic;
}

bool IrcChannel::isActive() const
{
    Q_D(const IrcChannel);
    return IrcBuffer::isActive() && d->joined > d->left;
}

/*!
    Parts the channel with an optional \a reason.

    This method is provided for convenience. It is equal to:
    \code
    IrcCommand* command = IrcCommand::createPart(channel->title(), reason);
    channel->sendCommand(command);
    \endcode

    \sa IrcBuffer::sendCommand(), IrcCommand::createPart()
 */
void IrcChannel::part(const QString& reason)
{
    sendCommand(IrcCommand::createPart(title(), reason));
}

#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const IrcChannel* channel)
{
    if (!channel)
        return debug << "IrcChannel(0x0) ";
    debug.nospace() << channel->metaObject()->className() << '(' << (void*) channel;
    if (!channel->objectName().isEmpty())
        debug.nospace() << ", name=" << qPrintable(channel->objectName());
    if (!channel->title().isEmpty())
        debug.nospace() << ", title=" << qPrintable(channel->title());
    debug.nospace() << ')';
    return debug.space();
}
#endif // QT_NO_DEBUG_STREAM

#include "moc_ircchannel.cpp"

IRC_END_NAMESPACE
<|endoftext|>


<commit_before>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
#include <cstring>

#include "Socket.h"

Socket::Socket()
{
  _socketDescriptor = -1;
}

Socket::~Socket()
{
}

bool Socket::start(int port)
{
  int status;

  struct sockaddr_in serverAddress;
  std::memset(&serverAddress, 0, sizeof(serverAddress));
  serverAddress.sin_family = AF_INET;
  serverAddress.sin_addr.s_addr = INADDR_ANY;  //TODO: set this properly
  serverAddress.sin_port = htons(port);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tCreating socket" << std::endl;
  _socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(_socketDescriptor < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while opening socket: " << _socketDescriptor << std::endl;
    return false;
  }

  int on = 1;
  status = setsockopt(_socketDescriptor, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError setting socket options: " << status << std::endl;
    return false;
  }

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBinding socket" << std::endl;
  status = bind(_socketDescriptor, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError binding socket to hostname: " << status << std::endl;
    return false;
  }

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBeginning socket listen" << std::endl;
  status = listen(_socketDescriptor, 5);
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError listening socket: " << status << std::endl;
    return false;
  }

  return true;
}

bool Socket::accept(Socket &clientConnection)
{
  struct sockaddr_in clientAddress;
  socklen_t clientAddressSize = sizeof(clientAddress);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBeginning connection accept" << std::endl;
  clientConnection._socketDescriptor = ::accept(_socketDescriptor, (struct sockaddr *) &clientAddress, &clientAddressSize);
  if(clientConnection._socketDescriptor < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while accepting connection: "
	                                         << clientConnection._socketDescriptor << std::endl;
    return false;
  }

  return true;
}

bool Socket::close()
{
  ::close(_socketDescriptor);
  return true;
}

bool Socket::send(std::string str)
{
  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tSending data" << std::endl;

  uint32_t header = htonl((uint32_t)str.size());
  unsigned char headerArray[sizeof(header)];
  std::memcpy(headerArray, &header, sizeof(header));

  if(::send(_socketDescriptor, headerArray, sizeof(headerArray), MSG_NOSIGNAL) >= 0) {
    return ( ::send(_socketDescriptor, str.c_str(), str.size(), MSG_NOSIGNAL) >= 0 );
  }

  return false;
}

int Socket::recv(std::string &str)
{
  int retval = 0;
  str = "";

  int bufferSize = 64*1024;
  char buffer[bufferSize + 1];
  std::memset(buffer, 0, bufferSize + 1);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tReceiving data" << std::endl;
  retval = ::recv(_socketDescriptor, buffer, bufferSize, 0);
  if(retval < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while recieving -- more than likely, this was an immediate disconnect from the client" << std::endl;
    return 0;
  }

  str = buffer;
  return retval;
}

<commit_msg>Setting timeout on socket::recv to prevent hangs in server<commit_after>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
#include <cstring>

#include "Socket.h"

Socket::Socket()
{
  _socketDescriptor = -1;
}

Socket::~Socket()
{
}

bool Socket::start(int port)
{
  int status;

  struct sockaddr_in serverAddress;
  std::memset(&serverAddress, 0, sizeof(serverAddress));
  serverAddress.sin_family = AF_INET;
  serverAddress.sin_addr.s_addr = INADDR_ANY;  //TODO: set this properly
  serverAddress.sin_port = htons(port);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tCreating socket" << std::endl;
  _socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if(_socketDescriptor < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while opening socket: " << _socketDescriptor << std::endl;
    return false;
  }

  int on = 1;
  status = setsockopt(_socketDescriptor, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on));
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError setting socket options: " << status << std::endl;
    return false;
  }

  struct timeval tv;
  tv.tv_sec = 10;
  status = setsockopt(_socketDescriptor, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError setting socket timeout options: " << status << std::endl;
    return false;
  }

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBinding socket" << std::endl;
  status = bind(_socketDescriptor, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError binding socket to hostname: " << status << std::endl;
    return false;
  }

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBeginning socket listen" << std::endl;
  status = listen(_socketDescriptor, 5);
  if(status < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError listening socket: " << status << std::endl;
    return false;
  }

  return true;
}

bool Socket::accept(Socket &clientConnection)
{
  struct sockaddr_in clientAddress;
  socklen_t clientAddressSize = sizeof(clientAddress);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tBeginning connection accept" << std::endl;
  clientConnection._socketDescriptor = ::accept(_socketDescriptor, (struct sockaddr *) &clientAddress, &clientAddressSize);
  if(clientConnection._socketDescriptor < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while accepting connection: "
	                                         << clientConnection._socketDescriptor << std::endl;
    return false;
  }

  return true;
}

bool Socket::close()
{
  ::close(_socketDescriptor);
  return true;
}

bool Socket::send(std::string str)
{
  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tSending data" << std::endl;

  uint32_t header = htonl((uint32_t)str.size());
  unsigned char headerArray[sizeof(header)];
  std::memcpy(headerArray, &header, sizeof(header));

  if(::send(_socketDescriptor, headerArray, sizeof(headerArray), MSG_NOSIGNAL) >= 0) {
    return ( ::send(_socketDescriptor, str.c_str(), str.size(), MSG_NOSIGNAL) >= 0 );
  }

  return false;
}

int Socket::recv(std::string &str)
{
  int retval = 0;
  str = "";

  int bufferSize = 64*1024;
  char buffer[bufferSize + 1];
  std::memset(buffer, 0, bufferSize + 1);

  std::cerr << __FILE__ << ":" << __LINE__ << "\t\tReceiving data" << std::endl;
  retval = ::recv(_socketDescriptor, buffer, bufferSize, 0);
  if(retval < 0) {
    std::cerr << __FILE__ << ":" << __LINE__ << "\t\tError while recieving -- more than likely, this was an immediate disconnect from the client" << std::endl;
    return 0;
  }

  str = buffer;
  return retval;
}
<|endoftext|>


<commit_before>#include "Globals.h"
#include "Engine.h"
#include "ModuleRender.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "SDL/include/SDL.h"

#define DEG2RAD(deg) (deg * M_PI / 180.0)

ModuleRender::ModuleRender()
{
	camera.x = camera.y = 0;
	camera.w = SCREEN_WIDTH * SCREEN_SIZE;
	camera.h = SCREEN_HEIGHT* SCREEN_SIZE;
}

// Destructor
ModuleRender::~ModuleRender()
{}

// Called before render is available
bool ModuleRender::Init()
{
	LOG("Creating Renderer context");
	bool ret = true;
	Uint32 flags = 0;

	if(VSYNC == true)
	{
		flags |= SDL_RENDERER_PRESENTVSYNC;
	}

	renderer = SDL_CreateRenderer(App->window->window, -1, flags);

	if(renderer == nullptr)
	{
		LOG("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}

	return ret;
}

update_status ModuleRender::PreUpdate()
{
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
	SDL_RenderClear(renderer);
	return UPDATE_CONTINUE;
}

// Called every draw update
update_status ModuleRender::Update()
{
	// debug camera
	int speed = 1;

	if(App->input->GetKey(SDL_SCANCODE_UP) == KEY_REPEAT)
		App->renderer->camera.y += speed;

	if(App->input->GetKey(SDL_SCANCODE_DOWN) == KEY_REPEAT)
		App->renderer->camera.y -= speed;

	if(App->input->GetKey(SDL_SCANCODE_LEFT) == KEY_REPEAT)
		App->renderer->camera.x += speed;

	if(App->input->GetKey(SDL_SCANCODE_RIGHT) == KEY_REPEAT)
		App->renderer->camera.x -= speed;

	bool ret = true;

	while (!_background.empty() && ret)
	{
		RenderData* data = _background.front();
		if (SDL_RenderCopy(renderer, data->texture, data->section, data->rect) != 0)
		{
			LOG("Cannot blit to screen. SDL_RenderCopy error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data);
		_background.pop();
	}

	while (!_foreground.empty() && ret)
	{
		RenderData* data = _foreground.top().second;

		SDL_RendererFlip flags = data->flip ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
		SDL_Point center = { 0, 0 };
		if (SDL_RenderCopyEx(renderer, data->texture, data->section, data->rect, 0, &center, flags) != 0)
		{
			LOG("Cannot blit to screen. SDL_RenderCopy error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data);
		_foreground.pop();
	}

	SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);

	while (!_quads.empty() && ret)
	{
		QuadData* data = _quads.front();
		SDL_SetRenderDrawColor(renderer, data->color->r, data->color->g, data->color->b, data->color->a);

		if (SDL_RenderFillRect(renderer, data->rect) != 0)
		{
			LOG("Cannot draw quad to screen. SDL_RenderFillRect error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data->color);
		RELEASE(data);
		_quads.pop();
	}

	return ret ? UPDATE_CONTINUE : UPDATE_ERROR;
}

update_status ModuleRender::PostUpdate()
{
	SDL_RenderPresent(renderer);
	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleRender::CleanUp()
{
	LOG("Destroying renderer");

	while (!_background.empty())
	{
		RenderData* data = _background.front();
		RELEASE(data->rect);
		RELEASE(data);
		_background.pop();
	}

	while (!_foreground.empty())
	{
		RenderData* data = _foreground.top().second;
		RELEASE(data->rect);
		RELEASE(data);
		_foreground.pop();
	}

	//Destroy window
	if(renderer != nullptr)
	{
		SDL_DestroyRenderer(renderer);
	}

	return true;
}

// Blit to screen
bool ModuleRender::BlitBackground(SDL_Texture* texture, int x, int y, SDL_Rect* section, float speed)
{
	bool ret = true;
	SDL_Rect* rect = new SDL_Rect;
	rect->x = (int)(camera.x * speed) + x * SCREEN_SIZE;
	rect->y = (int)(camera.y * speed) + y * SCREEN_SIZE;

	if(section != NULL)
	{
		rect->w = section->w;
		rect->h = section->h;
	}
	else
	{
		SDL_QueryTexture(texture, NULL, NULL, &rect->w, &rect->h);
	}

	if (rect->w > _background_height)
		_background_height = rect->h;

	rect->w *= SCREEN_SIZE;
	rect->h *= SCREEN_SIZE;

	_background.push(new RenderData({ false, texture, section, rect }));

	return ret;
}

bool ModuleRender::AbsoluteBlit(SDL_Texture* texture, int x, int y, int z, SDL_Rect* section, float speed, bool flip)
{
	bool ret = true;
	SDL_Rect* rect = new SDL_Rect;
	rect->x = (int)(camera.x * speed) + x * SCREEN_SIZE;
	y += cos(DEG2RAD(RenderingAngle)) * z;
	rect->y = (int)(camera.y * speed) + y * SCREEN_SIZE; // TODO: Add z to y

	if (section != NULL)
	{
		rect->w = section->w;
		rect->h = section->h;
	}
	else
	{
		SDL_QueryTexture(texture, NULL, NULL, &rect->w, &rect->h);
	}

	rect->w *= SCREEN_SIZE;
	rect->h *= SCREEN_SIZE;

	_foreground.emplace(z, new RenderData({ flip, texture, section, rect }));

	return ret;
}

bool ModuleRender::Blit(SDL_Texture* texture, int x, int y, int z, SDL_Rect* section, float speed, bool flip)
{
	if (_background_height)
		y = _background_height - y;
	z *= -1;

	return AbsoluteBlit(texture, x, y, z, section, speed, flip);
}

bool ModuleRender::AbsoluteDrawQuad(const SDL_Rect& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	bool ret = true;

	SDL_Color* color = new SDL_Color({ r,g,b,a });

	SDL_Rect* rec = new SDL_Rect(rect);
	if (use_camera)
	{
		rec->x = (int)(camera.x + rect.x * SCREEN_SIZE);
		rec->y = (int)(camera.y + rect.y * SCREEN_SIZE);
		rec->w *= SCREEN_SIZE;
		rec->h *= SCREEN_SIZE;
	}

	_quads.emplace(new QuadData({ rec, color }));

	return ret;
}

bool ModuleRender::AbsoluteDrawQuad(const iRectangle3& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	int y = rect.Position.y + cos(DEG2RAD(RenderingAngle)) * rect.Position.z;
	return AbsoluteDrawQuad({ rect.Position.x, y, rect.w, rect.h }, r, g, b, a, use_camera);
}

bool ModuleRender::DrawQuad(const iRectangle3& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	iRectangle3 rec = rect;
	if (_background_height)
		rec.Position.y = _background_height - rect.Position.y;
	rec.Position.z *= -1;

	return AbsoluteDrawQuad(rec, r, g, b, a, use_camera);
}

<commit_msg>Fix memory leak introduced with quads queue<commit_after>#include "Globals.h"
#include "Engine.h"
#include "ModuleRender.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "SDL/include/SDL.h"

#define DEG2RAD(deg) (deg * M_PI / 180.0)

ModuleRender::ModuleRender()
{
	camera.x = camera.y = 0;
	camera.w = SCREEN_WIDTH * SCREEN_SIZE;
	camera.h = SCREEN_HEIGHT* SCREEN_SIZE;
}

// Destructor
ModuleRender::~ModuleRender()
{}

// Called before render is available
bool ModuleRender::Init()
{
	LOG("Creating Renderer context");
	bool ret = true;
	Uint32 flags = 0;

	if(VSYNC == true)
	{
		flags |= SDL_RENDERER_PRESENTVSYNC;
	}

	renderer = SDL_CreateRenderer(App->window->window, -1, flags);

	if(renderer == nullptr)
	{
		LOG("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}

	return ret;
}

update_status ModuleRender::PreUpdate()
{
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
	SDL_RenderClear(renderer);
	return UPDATE_CONTINUE;
}

// Called every draw update
update_status ModuleRender::Update()
{
	// debug camera
	int speed = 1;

	if(App->input->GetKey(SDL_SCANCODE_UP) == KEY_REPEAT)
		App->renderer->camera.y += speed;

	if(App->input->GetKey(SDL_SCANCODE_DOWN) == KEY_REPEAT)
		App->renderer->camera.y -= speed;

	if(App->input->GetKey(SDL_SCANCODE_LEFT) == KEY_REPEAT)
		App->renderer->camera.x += speed;

	if(App->input->GetKey(SDL_SCANCODE_RIGHT) == KEY_REPEAT)
		App->renderer->camera.x -= speed;

	bool ret = true;

	while (!_background.empty() && ret)
	{
		RenderData* data = _background.front();
		if (SDL_RenderCopy(renderer, data->texture, data->section, data->rect) != 0)
		{
			LOG("Cannot blit to screen. SDL_RenderCopy error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data);
		_background.pop();
	}

	while (!_foreground.empty() && ret)
	{
		RenderData* data = _foreground.top().second;

		SDL_RendererFlip flags = data->flip ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
		SDL_Point center = { 0, 0 };
		if (SDL_RenderCopyEx(renderer, data->texture, data->section, data->rect, 0, &center, flags) != 0)
		{
			LOG("Cannot blit to screen. SDL_RenderCopy error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data);
		_foreground.pop();
	}

	SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);

	while (!_quads.empty() && ret)
	{
		QuadData* data = _quads.front();
		SDL_SetRenderDrawColor(renderer, data->color->r, data->color->g, data->color->b, data->color->a);

		if (SDL_RenderFillRect(renderer, data->rect) != 0)
		{
			LOG("Cannot draw quad to screen. SDL_RenderFillRect error: %s", SDL_GetError());
			ret = false;
		}

		RELEASE(data->rect);
		RELEASE(data->color);
		RELEASE(data);
		_quads.pop();
	}

	return ret ? UPDATE_CONTINUE : UPDATE_ERROR;
}

update_status ModuleRender::PostUpdate()
{
	SDL_RenderPresent(renderer);
	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleRender::CleanUp()
{
	LOG("Destroying renderer");

	while (!_background.empty())
	{
		RenderData* data = _background.front();
		RELEASE(data->rect);
		RELEASE(data);
		_background.pop();
	}

	while (!_foreground.empty())
	{
		RenderData* data = _foreground.top().second;
		RELEASE(data->rect);
		RELEASE(data);
		_foreground.pop();
	}

	while (!_quads.empty())
	{
		QuadData* data = _quads.front();
		RELEASE(data->rect);
		RELEASE(data->color);
		_quads.pop();
	}

	//Destroy window
	if(renderer != nullptr)
	{
		SDL_DestroyRenderer(renderer);
	}

	return true;
}

// Blit to screen
bool ModuleRender::BlitBackground(SDL_Texture* texture, int x, int y, SDL_Rect* section, float speed)
{
	bool ret = true;
	SDL_Rect* rect = new SDL_Rect;
	rect->x = (int)(camera.x * speed) + x * SCREEN_SIZE;
	rect->y = (int)(camera.y * speed) + y * SCREEN_SIZE;

	if(section != NULL)
	{
		rect->w = section->w;
		rect->h = section->h;
	}
	else
	{
		SDL_QueryTexture(texture, NULL, NULL, &rect->w, &rect->h);
	}

	if (rect->w > _background_height)
		_background_height = rect->h;

	rect->w *= SCREEN_SIZE;
	rect->h *= SCREEN_SIZE;

	_background.push(new RenderData({ false, texture, section, rect }));

	return ret;
}

bool ModuleRender::AbsoluteBlit(SDL_Texture* texture, int x, int y, int z, SDL_Rect* section, float speed, bool flip)
{
	bool ret = true;
	SDL_Rect* rect = new SDL_Rect;
	rect->x = (int)(camera.x * speed) + x * SCREEN_SIZE;
	y += cos(DEG2RAD(RenderingAngle)) * z;
	rect->y = (int)(camera.y * speed) + y * SCREEN_SIZE; // TODO: Add z to y

	if (section != NULL)
	{
		rect->w = section->w;
		rect->h = section->h;
	}
	else
	{
		SDL_QueryTexture(texture, NULL, NULL, &rect->w, &rect->h);
	}

	rect->w *= SCREEN_SIZE;
	rect->h *= SCREEN_SIZE;

	_foreground.emplace(z, new RenderData({ flip, texture, section, rect }));

	return ret;
}

bool ModuleRender::Blit(SDL_Texture* texture, int x, int y, int z, SDL_Rect* section, float speed, bool flip)
{
	if (_background_height)
		y = _background_height - y;
	z *= -1;

	return AbsoluteBlit(texture, x, y, z, section, speed, flip);
}

bool ModuleRender::AbsoluteDrawQuad(const SDL_Rect& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	bool ret = true;

	SDL_Color* color = new SDL_Color({ r,g,b,a });

	SDL_Rect* rec = new SDL_Rect(rect);
	if (use_camera)
	{
		rec->x = (int)(camera.x + rect.x * SCREEN_SIZE);
		rec->y = (int)(camera.y + rect.y * SCREEN_SIZE);
		rec->w *= SCREEN_SIZE;
		rec->h *= SCREEN_SIZE;
	}

	_quads.emplace(new QuadData({ rec, color }));

	return ret;
}

bool ModuleRender::AbsoluteDrawQuad(const iRectangle3& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	int y = rect.Position.y + cos(DEG2RAD(RenderingAngle)) * rect.Position.z;
	return AbsoluteDrawQuad({ rect.Position.x, y, rect.w, rect.h }, r, g, b, a, use_camera);
}

bool ModuleRender::DrawQuad(const iRectangle3& rect, Uint8 r, Uint8 g, Uint8 b, Uint8 a, bool use_camera)
{
	iRectangle3 rec = rect;
	if (_background_height)
		rec.Position.y = _background_height - rect.Position.y;
	rec.Position.z *= -1;

	return AbsoluteDrawQuad(rec, r, g, b, a, use_camera);
}

<|endoftext|>


<commit_before>#ifndef VPP_DRAW_HH_
# define VPP_DRAW_HH_

namespace vpp
{
  namespace draw
  {
    using namespace vpp;
    template <typename I, typename V>
    void line2d(I out, vint2 a, vint2 b, V color)
    {
      int x0 = a[1]; int y0 = a[0];
      int x1 = b[1]; int y1 = b[0];

      int steep = ::abs(y1 - y0) > ::abs(x1 - x0);

      if (steep)
      {
        std::swap(x0, y0);
        std::swap(x1, y1);
      }

      if (x0 > x1)
      {
        std::swap(x0, x1);
        std::swap(y0, y1);
      }

      int deltax = x1 - x0;
      int deltay = ::abs(y1 - y0);
      float error = 0.f;
      float deltaerr = deltay / float(deltax);
      int ystep;
      int y = y0;
      if (y0 < y1) ystep = 1; else ystep = -1;

      for (int x = x0 + 1; x <= x1; x++)
      {
        vint2 to_plot;
        if (steep)
          to_plot = vint2{x, y};
        else
          to_plot = vint2{y, x};

        if (out.has(to_plot))
          out(to_plot) = color;

        error = error + deltaerr;
        if (error >= 0.5)
        {
          y = y + ystep;
          error = error - 1.0;
        }
      }
    }

    template <typename I, typename V>
    void c9(I out, vint2 a, V color)
    {
      for (int r = -1; r <= 1; r++)
        for (int c = -1; c <= 1; c++)
        {
          vint2 n = a + vint2{r, c};
          if (out.has(n))
            out(n) = color;
        }
    }
  }
}

#endif
<commit_msg>Add draw::square.<commit_after>#ifndef VPP_DRAW_HH_
# define VPP_DRAW_HH_

#include <vpp/core/vector.hh>

namespace vpp
{
  namespace draw
  {
    using namespace vpp;
    template <typename I, typename V>
    void line2d(I out, vint2 a, vint2 b, V color)
    {
      int x0 = a[1]; int y0 = a[0];
      int x1 = b[1]; int y1 = b[0];

      int steep = ::abs(y1 - y0) > ::abs(x1 - x0);

      if (steep)
      {
        std::swap(x0, y0);
        std::swap(x1, y1);
      }

      if (x0 > x1)
      {
        std::swap(x0, x1);
        std::swap(y0, y1);
      }

      int deltax = x1 - x0;
      int deltay = ::abs(y1 - y0);
      float error = 0.f;
      float deltaerr = deltay / float(deltax);
      int ystep;
      int y = y0;
      if (y0 < y1) ystep = 1; else ystep = -1;

      for (int x = x0 + 1; x <= x1; x++)
      {
        vint2 to_plot;
        if (steep)
          to_plot = vint2{x, y};
        else
          to_plot = vint2{y, x};

        if (out.has(to_plot))
          out(to_plot) = color;

        error = error + deltaerr;
        if (error >= 0.5)
        {
          y = y + ystep;
          error = error - 1.0;
        }
      }
    }

    template <typename I, typename V>
    void c9(I out, vint2 a, V color)
    {
      for (int r = -1; r <= 1; r++)
        for (int c = -1; c <= 1; c++)
        {
          vint2 n = a + vint2{r, c};
          if (out.has(n))
            out(n) = color;
        }
    }

    template <typename I, typename V>
    void square(I out, vint2 a, int size, V color)
    {
      for (int r = -size/2; r <= size/2; r++)
        for (int c = -size/2; c <= size/2; c++)
        {
          vint2 n = a + vint2{r, c};
          if (out.has(n))
            out(n) = color;
        }
    }
  }
}

#endif
<|endoftext|>


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

#include "vtkOBJWriter.h"

#include "vtkActorCollection.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCellArray.h"
#include "vtkDataSet.h"
#include "vtkFloatArray.h"
#include "vtkGeometryFilter.h"
#include "vtkMapper.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRendererCollection.h"
#include "vtkTransform.h"
#include "vtkSmartPointer.h"
#include "vtkInformationVector.h"
#include "vtkInformation.h"

vtkStandardNewMacro(vtkOBJWriter);

vtkOBJWriter::vtkOBJWriter()
{
  this->FileName = NULL;

  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(0);

}

vtkOBJWriter::~vtkOBJWriter()
{
  if ( this->FileName )
    {
    delete [] this->FileName;
    }
}

int vtkOBJWriter::RequestData(vtkInformation *vtkNotUsed(request),
                               vtkInformationVector **inputVector,
                               vtkInformationVector *vtkNotUsed(outputVector))
{

  //Get the input
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkPolyData *pd = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  //open the file for writing
  std::ofstream fout(this->FileName);

  //write header
  fout << "# wavefront obj file written by the visualization toolkit" << endl << endl;

  fout << "mtllib NONE" << endl << endl;

  vtkSmartPointer<vtkPointData> pntData;
  vtkSmartPointer<vtkPoints> points;
  vtkSmartPointer<vtkDataArray> tcoords;
  int i, i1, i2, idNext;
  int idStart = 1;
  double *tempd;
  double p[3];
  vtkCellArray *cells;
  vtkIdType npts = 0;
  vtkIdType *indx = 0;

  // write out the points
  for (i = 0; i < pd->GetNumberOfPoints(); i++)
    {
    pd->GetPoint(i, p);
    fout << "v " << p[0] << " " << p[1] << " " << p[2] << endl;
    }

  idNext = idStart + static_cast<int>(pd->GetNumberOfPoints());

  // write out the point data

  vtkSmartPointer<vtkDataArray> normals = pd->GetPointData()->GetNormals();
  if(normals)
    {
      for (i = 0; i < normals->GetNumberOfTuples(); i++)
        {
        normals->GetTuple(i, p);
        fout << "vn " << p[0] << " " << p[1] << " " << p[2] << endl;
        }
    }

  tcoords = pd->GetPointData()->GetTCoords();
  if (tcoords)
    {
    for (i = 0; i < tcoords->GetNumberOfTuples(); i++)
      {
      tcoords->GetTuple(i, p);
      fout << "vt " << p[0] << " " << p[1] << endl;
      }
    }

  // write out a group name and material
  fout << endl << "g grp" << idStart << endl;
  fout << "usemtl mtlNONE" << endl;

  // write out verts if any
  if (pd->GetNumberOfVerts() > 0)
    {
    cells = pd->GetVerts();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
        fout << "p ";
        for (i = 0; i < npts; i++)
          {
          fout << static_cast<int>(indx[i])+idStart << " ";
          }
        fout << endl;
      }
    }

  // write out lines if any
  if (pd->GetNumberOfLines() > 0)
    {
    cells = pd->GetLines();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
        fout << "l ";
        if (tcoords)
          {
          for (i = 0; i < npts; i++)
            {
            fout << static_cast<int>(indx[i])+idStart << "/" << static_cast<int>(indx[i]) + idStart << " ";
            }
          }
        else
          {
          for (i = 0; i < npts; i++)
            {
            fout << static_cast<int>(indx[i])+idStart << " ";
            }
          }
        fout << endl;
      }
    }

  // write out polys if any
  if (pd->GetNumberOfPolys() > 0)
    {
    cells = pd->GetPolys();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
      fout << "f ";
      for (i = 0; i < npts; i++)
        {
        if (normals)
          {
          if (tcoords)
            {
            fout << static_cast<int>(indx[i])+idStart << "/" << static_cast<int>(indx[i])+ idStart << "/" << static_cast<int>(indx[i]) + idStart << " ";
            }
          else
            {
            fout << static_cast<int>(indx[i])+idStart << "//" << static_cast<int>(indx[i]) + idStart << " ";
            }
          }
        else
          {
          if (tcoords)
            {
            fout << static_cast<int>(indx[i])+idStart << " " << static_cast<int>(indx[i]) + idStart << " ";
            }
          else
            {
            fout << static_cast<int>(indx[i])+idStart << " ";
            }
          }
        }
        fout << endl;
      }
    }

  // write out tstrips if any
  if (pd->GetNumberOfStrips() > 0)
    {
    cells = pd->GetStrips();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
      for (i = 2; i < npts; i++)
        {
        if (i%2)
        {
            i1 = i - 1;
            i2 = i - 2;
        }
        else
        {
            i1 = i - 1;
            i2 = i - 2;
        }
        if(normals)
          {
          if (tcoords)
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "/" << static_cast<int>(indx[i1]) + idStart << "/" <<  static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2])+ idStart << "/" << static_cast<int>(indx[i2]) + idStart << "/" << static_cast<int>(indx[i2]) + idStart << " ";
             fout << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << endl;
            }
          else
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "//" << static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2]) + idStart << "//" << static_cast<int>(indx[i2]) + idStart << " ";
            fout << static_cast<int>(indx[i]) + idStart << "//" << static_cast<int>(indx[i]) + idStart << endl;
            }
          }
        else
          {
          if (tcoords)
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "/" << static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2]) + idStart << "/" << static_cast<int>(indx[i2]) + idStart << " ";
            fout << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << endl;
            }
          else
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << " " << static_cast<int>(indx[i2]) + idStart << " " << static_cast<int>(indx[i]) + idStart << endl;
            }
          }
        }
      }
    }

  idStart = idNext;

}

void vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if (this->FileName)
    {
    os << indent << "FileName: " << this->FileName << "\n";
    }
  else
    {
    os << indent << "FileName: (null)\n";
    }
}

<commit_msg>Add VTK copyright.<commit_after>/*=========================================================================
 *
 *  Copyright David Doria 2011 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

/*=========================================================================
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.
=========================================================================*/

#include "vtkOBJWriter.h"

#include "vtkActorCollection.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCellArray.h"
#include "vtkDataSet.h"
#include "vtkFloatArray.h"
#include "vtkGeometryFilter.h"
#include "vtkMapper.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkRenderWindow.h"
#include "vtkRendererCollection.h"
#include "vtkTransform.h"
#include "vtkSmartPointer.h"
#include "vtkInformationVector.h"
#include "vtkInformation.h"

vtkStandardNewMacro(vtkOBJWriter);

vtkOBJWriter::vtkOBJWriter()
{
  this->FileName = NULL;

  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(0);

}

vtkOBJWriter::~vtkOBJWriter()
{
  if ( this->FileName )
    {
    delete [] this->FileName;
    }
}

int vtkOBJWriter::RequestData(vtkInformation *vtkNotUsed(request),
                               vtkInformationVector **inputVector,
                               vtkInformationVector *vtkNotUsed(outputVector))
{

  //Get the input
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkPolyData *pd = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  //open the file for writing
  std::ofstream fout(this->FileName);

  //write header
  fout << "# wavefront obj file written by the visualization toolkit" << endl << endl;

  fout << "mtllib NONE" << endl << endl;

  vtkSmartPointer<vtkPointData> pntData;
  vtkSmartPointer<vtkPoints> points;
  vtkSmartPointer<vtkDataArray> tcoords;
  int i, i1, i2, idNext;
  int idStart = 1;
  double *tempd;
  double p[3];
  vtkCellArray *cells;
  vtkIdType npts = 0;
  vtkIdType *indx = 0;

  // write out the points
  for (i = 0; i < pd->GetNumberOfPoints(); i++)
    {
    pd->GetPoint(i, p);
    fout << "v " << p[0] << " " << p[1] << " " << p[2] << endl;
    }

  idNext = idStart + static_cast<int>(pd->GetNumberOfPoints());

  // write out the point data

  vtkSmartPointer<vtkDataArray> normals = pd->GetPointData()->GetNormals();
  if(normals)
    {
      for (i = 0; i < normals->GetNumberOfTuples(); i++)
        {
        normals->GetTuple(i, p);
        fout << "vn " << p[0] << " " << p[1] << " " << p[2] << endl;
        }
    }

  tcoords = pd->GetPointData()->GetTCoords();
  if (tcoords)
    {
    for (i = 0; i < tcoords->GetNumberOfTuples(); i++)
      {
      tcoords->GetTuple(i, p);
      fout << "vt " << p[0] << " " << p[1] << endl;
      }
    }

  // write out a group name and material
  fout << endl << "g grp" << idStart << endl;
  fout << "usemtl mtlNONE" << endl;

  // write out verts if any
  if (pd->GetNumberOfVerts() > 0)
    {
    cells = pd->GetVerts();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
        fout << "p ";
        for (i = 0; i < npts; i++)
          {
          fout << static_cast<int>(indx[i])+idStart << " ";
          }
        fout << endl;
      }
    }

  // write out lines if any
  if (pd->GetNumberOfLines() > 0)
    {
    cells = pd->GetLines();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
        fout << "l ";
        if (tcoords)
          {
          for (i = 0; i < npts; i++)
            {
            fout << static_cast<int>(indx[i])+idStart << "/" << static_cast<int>(indx[i]) + idStart << " ";
            }
          }
        else
          {
          for (i = 0; i < npts; i++)
            {
            fout << static_cast<int>(indx[i])+idStart << " ";
            }
          }
        fout << endl;
      }
    }

  // write out polys if any
  if (pd->GetNumberOfPolys() > 0)
    {
    cells = pd->GetPolys();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
      fout << "f ";
      for (i = 0; i < npts; i++)
        {
        if (normals)
          {
          if (tcoords)
            {
            fout << static_cast<int>(indx[i])+idStart << "/" << static_cast<int>(indx[i])+ idStart << "/" << static_cast<int>(indx[i]) + idStart << " ";
            }
          else
            {
            fout << static_cast<int>(indx[i])+idStart << "//" << static_cast<int>(indx[i]) + idStart << " ";
            }
          }
        else
          {
          if (tcoords)
            {
            fout << static_cast<int>(indx[i])+idStart << " " << static_cast<int>(indx[i]) + idStart << " ";
            }
          else
            {
            fout << static_cast<int>(indx[i])+idStart << " ";
            }
          }
        }
        fout << endl;
      }
    }

  // write out tstrips if any
  if (pd->GetNumberOfStrips() > 0)
    {
    cells = pd->GetStrips();
    for (cells->InitTraversal(); cells->GetNextCell(npts,indx); )
      {
      for (i = 2; i < npts; i++)
        {
        if (i%2)
        {
            i1 = i - 1;
            i2 = i - 2;
        }
        else
        {
            i1 = i - 1;
            i2 = i - 2;
        }
        if(normals)
          {
          if (tcoords)
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "/" << static_cast<int>(indx[i1]) + idStart << "/" <<  static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2])+ idStart << "/" << static_cast<int>(indx[i2]) + idStart << "/" << static_cast<int>(indx[i2]) + idStart << " ";
             fout << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << endl;
            }
          else
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "//" << static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2]) + idStart << "//" << static_cast<int>(indx[i2]) + idStart << " ";
            fout << static_cast<int>(indx[i]) + idStart << "//" << static_cast<int>(indx[i]) + idStart << endl;
            }
          }
        else
          {
          if (tcoords)
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << "/" << static_cast<int>(indx[i1]) + idStart << " ";
            fout << static_cast<int>(indx[i2]) + idStart << "/" << static_cast<int>(indx[i2]) + idStart << " ";
            fout << static_cast<int>(indx[i]) + idStart << "/" << static_cast<int>(indx[i]) + idStart << endl;
            }
          else
            {
            fout << "f " << static_cast<int>(indx[i1]) + idStart << " " << static_cast<int>(indx[i2]) + idStart << " " << static_cast<int>(indx[i]) + idStart << endl;
            }
          }
        }
      }
    }

  idStart = idNext;

}

void vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if (this->FileName)
    {
    os << indent << "FileName: " << this->FileName << "\n";
    }
  else
    {
    os << indent << "FileName: (null)\n";
    }
}

<|endoftext|>