<commit_before>#pragma once

/*
Copyright (c) 2014, Jeff Koftinoff <jeffk@jdkoftinoff.com> and J.D. Koftinoff Software, Ltd.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "Dap_World.hpp"
#include "Dap_Vec.hpp"
#include "Dap_Traits.hpp"
#include "Dap_Twist.hpp"

namespace Dap
{

/**
 * 3 dimensional array block indexed by Width, Height, and Depth
 */
template <typename T, typename TwistType, std::size_t Width, std::size_t Height = 1, std::size_t Depth = 1>
struct Block
{
    using twist_type = TwistType;
    using value_type = T;
    using twist_array_type = twist_array<value_type, twist_type, Width, Height, Depth>;
    using array_type = typename twist_array_type::type;
    static const size_t width = Width;
    static const size_t height = Height;
    static const size_t depth = Depth;

    static const size_t raw_index0_size = twist_array_type::raw_index0_size;
    static const size_t raw_index1_size = twist_array_type::raw_index1_size;
    static const size_t raw_index2_size = twist_array_type::raw_index2_size;

    array_type content;
};

/**
 * Traits for unrotated array block
 */
template <typename T, typename TwistType, size_t Width, size_t Height, size_t Depth>
struct Traits<Block<T, TwistType, Width, Height, Depth> >
{
    using value_type = T;
    using twist_type = TwistType;
    using container_type = Block<T, twist_type, Width, Height, Depth>;
    using twist_array_type = typename container_type::twist_array_type;
    using array_type = typename container_type::array_type;

    static const size_t width = Width;
    static const size_t height = Height;
    static const size_t depth = Depth;

    static const size_t raw_index0_size = twist_array_type::raw_index0_size;
    static const size_t raw_index1_size = twist_array_type::raw_index1_size;
    static const size_t raw_index2_size = twist_array_type::raw_index2_size;
};

template <typename ContainerT>
auto get( ContainerT &c,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::get( c.content, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto get( ContainerT const &c,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::get( c.content, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto set( ContainerT &c,
          typename Traits<ContainerT>::value_type v,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> void
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    twist_array_type::set( c.content, v, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto rawget( ContainerT &c,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::rawget( c.content, i0, i1, i2 );
}

template <typename ContainerT>
auto rawget( ContainerT const &c,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::rawget( c.content, i0, i1, i2 );
}

template <typename ContainerT>
auto rawset( ContainerT &c,
             typename Traits<ContainerT>::value_type v,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> void
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    twist_array_type::rawset( c.content, v, i0, i1, i2 );
}

template <typename ContainerT, typename Functor>
void apply_block( ContainerT &srcdest, Functor f, typename Traits<ContainerT>::twist_array_type * = 0 )
{
    using ContainerTraits = Traits<ContainerT>;
    using ContainerTwistType = typename ContainerTraits::twist_type;
    using ValueType = typename ContainerTraits::value_type;

    for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ContainerTwistType::width_pos_from( pos );
                std::size_t h = ContainerTwistType::height_pos_from( pos );
                std::size_t d = ContainerTwistType::depth_pos_from( pos );

                ValueType &v = rawget( srcdest.content, w, h, d );
                v = f( v, w, h, d );
            }
        }
    }
}

template <typename SourceContainerT, typename DestinationContainerT, typename Functor>
auto apply_block( SourceContainerT const &src,
                  DestinationContainerT &dest,
                  Functor f,
                  typename Traits<SourceContainerT>::twist_array_type * = 0,
                  typename Traits<DestinationContainerT>::twist_array_type * = 0 ) -> void
{
    using SourceContainerTraits = Traits<SourceContainerT>;
    using DestinationContainerTraits = Traits<DestinationContainerT>;
    using DestinationContainerTwistType = typename DestinationContainerTraits::twist_type;
    using SourceValueType = typename SourceContainerTraits::value_type;
    using DestinationValueType = typename DestinationContainerTraits::value_type;

    static_assert( SourceContainerTraits::width == DestinationContainerTraits::width,
                   "Width different between Source and Destination" );
    static_assert( SourceContainerTraits::height == DestinationContainerTraits::height,
                   "Height different between Source and Destination" );
    static_assert( SourceContainerTraits::depth == DestinationContainerTraits::depth,
                   "Depth different between Source and Destination" );

    for ( std::size_t a = 0; a < DestinationContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < DestinationContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < DestinationContainerTraits::raw_index2_size; ++c )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = DestinationContainerTwistType::width_pos_from( pos );
                std::size_t h = DestinationContainerTwistType::height_pos_from( pos );
                std::size_t d = DestinationContainerTwistType::depth_pos_from( pos );

                DestinationValueType v = f( get( src.content, w, h, d ), w, h, d );
                rawset( dest.content, v, w, h, d );
            }
        }
    }
}

template <typename Container1T, typename Container2T, typename ResultContainerT, typename Functor>
auto apply_block( Container1T const &c1,
                  Container2T const &c2,
                  ResultContainerT &r,
                  Functor f,
                  typename Traits<Container1T>::twist_array_type * = 0,
                  typename Traits<Container2T>::twist_array_type * = 0,
                  typename Traits<ResultContainerT>::twist_array_type * = 0 ) -> void
{
    using Container1Traits = Traits<Container1T>;
    using Container2Traits = Traits<Container2T>;
    using ResultContainerTraits = Traits<ResultContainerT>;
    using ResultContainerTwistType = typename ResultContainerTraits::twist_type;
    using ValueType1 = typename Container1Traits::value_type;
    using ValueType2 = typename Container2Traits::value_type;
    using ValueTypeResult = typename ResultContainerTraits::value_type;

    static_assert( Container1Traits::width == Container2Traits::width, "Width different between Source and Destination" );
    static_assert( Container1Traits::height == Container2Traits::height, "Height different between Source and Destination" );
    static_assert( Container1Traits::depth == Container2Traits::depth, "Depth different between Source and Destination" );

    for ( std::size_t a = 0; a < ResultContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < ResultContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < ResultContainerTraits::raw_index2_size; ++c )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ResultContainerTwistType::width_pos_from( pos );
                std::size_t h = ResultContainerTwistType::height_pos_from( pos );
                std::size_t d = ResultContainerTwistType::depth_pos_from( pos );

                ValueTypeResult v = f( get( c1.content, w, h, d ), get( c2.content, w, h, d ), w, h, d );
                rawset( r.content, v, w, h, d );
            }
        }
    }
}

template <typename TwistType, std::size_t Width, std::size_t Height, std::size_t Depth, typename T>
auto make_block( T elem ) -> Block<T, TwistType, Width, Height, Depth>
{
    using Container = Block<T, TwistType, Width, Height, Depth>;
    using ContainerTraits = Traits<Container>;
    Container r;

    for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
            {
                rawset( r, elem, a, b, c );
            }
        }
    }

    return r;
}

template <typename T, typename TwistType, std::size_t Width, std::size_t Height, std::size_t Depth, typename Functor>
auto fill_block( Functor f ) -> Block<T, TwistType, Width, Height, Depth>
{
    using Container = Block<T, TwistType, Width, Height, Depth>;
    using ContainerTraits = Traits<Container>;
    using ContainerTwistType = typename Container::twist_type;
    Container r;

    for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ContainerTwistType::width_pos_from( pos );
                std::size_t h = ContainerTwistType::height_pos_from( pos );
                std::size_t d = ContainerTwistType::depth_pos_from( pos );

                rawset( r, f( w, h, d ), a, b, c );
            }
        }
    }

    return r;
}

template <int TwistAmount, typename InputContainerType>
auto twist_block( InputContainerType const &input )
    -> Block<typename Traits<InputContainerType>::value_type,
             typename Twister<typename InputContainerType::twist_type, TwistAmount>::output_twist,
             Traits<InputContainerType>::width,
             Traits<InputContainerType>::height,
             Traits<InputContainerType>::depth>
{
    using InputContainerTwistType = typename InputContainerType::twist_type;
    using InputContainerTraits = Traits<InputContainerType>;
    using OutputContainerType = Block<typename Traits<InputContainerType>::value_type,
                                      typename Twister<typename InputContainerType::twist_type, TwistAmount>::output_twist,
                                      InputContainerTraits::width,
                                      InputContainerTraits::height,
                                      InputContainerTraits::depth>;
    using OutputContainerTraits = Traits<OutputContainerType>;
    using OutputContainerTwistType = typename OutputContainerType::twist_type;

    OutputContainerType r;

    for ( std::size_t a = 0; a < OutputContainerTraits::raw_index0_size; ++a )
    {
        for ( std::size_t b = 0; b < OutputContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t c = 0; c < OutputContainerTraits::raw_index2_size; ++c )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = InputContainerTwistType::width_pos_from( pos );
                std::size_t h = InputContainerTwistType::height_pos_from( pos );
                std::size_t d = InputContainerTwistType::depth_pos_from( pos );

                rawset( r, get( input, w, h, d ), a, b, c );
            }
        }
    }

    return r;
}
}
<commit_msg>reverse ordering of nested loops<commit_after>#pragma once

/*
Copyright (c) 2014, Jeff Koftinoff <jeffk@jdkoftinoff.com> and J.D. Koftinoff Software, Ltd.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "Dap_World.hpp"
#include "Dap_Vec.hpp"
#include "Dap_Traits.hpp"
#include "Dap_Twist.hpp"
#include <iostream>

namespace Dap
{

/**
 * 3 dimensional array block indexed by Width, Height, and Depth
 */
template <typename T, typename TwistType, std::size_t Width, std::size_t Height = 1, std::size_t Depth = 1>
struct Block
{
    using twist_type = TwistType;
    using value_type = T;
    using twist_array_type = twist_array<value_type, twist_type, Width, Height, Depth>;
    using array_type = typename twist_array_type::type;
    static const size_t width = Width;
    static const size_t height = Height;
    static const size_t depth = Depth;

    static const size_t raw_index0_size = twist_array_type::raw_index0_size;
    static const size_t raw_index1_size = twist_array_type::raw_index1_size;
    static const size_t raw_index2_size = twist_array_type::raw_index2_size;

    array_type content;
};

/**
 * Traits for unrotated array block
 */
template <typename T, typename TwistType, size_t Width, size_t Height, size_t Depth>
struct Traits<Block<T, TwistType, Width, Height, Depth> >
{
    using value_type = T;
    using twist_type = TwistType;
    using container_type = Block<T, twist_type, Width, Height, Depth>;
    using twist_array_type = typename container_type::twist_array_type;
    using array_type = typename container_type::array_type;

    static const size_t width = Width;
    static const size_t height = Height;
    static const size_t depth = Depth;

    static const size_t raw_index0_size = twist_array_type::raw_index0_size;
    static const size_t raw_index1_size = twist_array_type::raw_index1_size;
    static const size_t raw_index2_size = twist_array_type::raw_index2_size;
};

template <typename ContainerT>
auto get( ContainerT &c,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::get( c.content, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto get( ContainerT const &c,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::get( c.content, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto set( ContainerT &c,
          typename Traits<ContainerT>::value_type v,
          std::size_t width_pos = 0,
          std::size_t height_pos = 0,
          std::size_t depth_pos = 0,
          typename Traits<ContainerT>::twist_array_type * = 0 ) -> void
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    twist_array_type::set( c.content, v, width_pos, height_pos, depth_pos );
}

template <typename ContainerT>
auto rawget( ContainerT &c,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::rawget( c.content, i0, i1, i2 );
}

template <typename ContainerT>
auto rawget( ContainerT const &c,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> typename Traits<ContainerT>::value_type &
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    return twist_array_type::rawget( c.content, i0, i1, i2 );
}

template <typename ContainerT>
auto rawset( ContainerT &c,
             typename Traits<ContainerT>::value_type v,
             std::size_t i0 = 0,
             std::size_t i1 = 0,
             std::size_t i2 = 0,
             typename Traits<ContainerT>::twist_array_type * = 0 ) -> void
{
    using twist_array_type = typename Traits<ContainerT>::twist_array_type;
    twist_array_type::rawset( c.content, v, i0, i1, i2 );
}

template <typename ContainerT, typename Functor>
void apply_block( ContainerT &srcdest, Functor f, typename Traits<ContainerT>::twist_array_type * = 0 )
{
    using ContainerTraits = Traits<ContainerT>;
    using ContainerTwistType = typename ContainerTraits::twist_type;
    using ValueType = typename ContainerTraits::value_type;

    for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ContainerTwistType::width_pos_from( pos );
                std::size_t h = ContainerTwistType::height_pos_from( pos );
                std::size_t d = ContainerTwistType::depth_pos_from( pos );

                ValueType &v = rawget( srcdest.content, w, h, d );
                v = f( v, w, h, d );
            }
        }
    }
}

template <typename SourceContainerT, typename DestinationContainerT, typename Functor>
auto apply_block( SourceContainerT const &src,
                  DestinationContainerT &dest,
                  Functor f,
                  typename Traits<SourceContainerT>::twist_array_type * = 0,
                  typename Traits<DestinationContainerT>::twist_array_type * = 0 ) -> void
{
    using SourceContainerTraits = Traits<SourceContainerT>;
    using DestinationContainerTraits = Traits<DestinationContainerT>;
    using DestinationContainerTwistType = typename DestinationContainerTraits::twist_type;
    using SourceValueType = typename SourceContainerTraits::value_type;
    using DestinationValueType = typename DestinationContainerTraits::value_type;

    static_assert( SourceContainerTraits::width == DestinationContainerTraits::width,
                   "Width different between Source and Destination" );
    static_assert( SourceContainerTraits::height == DestinationContainerTraits::height,
                   "Height different between Source and Destination" );
    static_assert( SourceContainerTraits::depth == DestinationContainerTraits::depth,
                   "Depth different between Source and Destination" );

    for ( std::size_t c = 0; c < DestinationContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < DestinationContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < DestinationContainerTraits::raw_index0_size; ++a )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = DestinationContainerTwistType::width_pos_from( pos );
                std::size_t h = DestinationContainerTwistType::height_pos_from( pos );
                std::size_t d = DestinationContainerTwistType::depth_pos_from( pos );

                DestinationValueType v = f( get( src.content, w, h, d ), w, h, d );
                rawset( dest.content, v, w, h, d );
            }
        }
    }
}

template <typename Container1T, typename Container2T, typename ResultContainerT, typename Functor>
auto apply_block( Container1T const &c1,
                  Container2T const &c2,
                  ResultContainerT &r,
                  Functor f,
                  typename Traits<Container1T>::twist_array_type * = 0,
                  typename Traits<Container2T>::twist_array_type * = 0,
                  typename Traits<ResultContainerT>::twist_array_type * = 0 ) -> void
{
    using Container1Traits = Traits<Container1T>;
    using Container2Traits = Traits<Container2T>;
    using ResultContainerTraits = Traits<ResultContainerT>;
    using ResultContainerTwistType = typename ResultContainerTraits::twist_type;
    using ValueType1 = typename Container1Traits::value_type;
    using ValueType2 = typename Container2Traits::value_type;
    using ValueTypeResult = typename ResultContainerTraits::value_type;

    static_assert( Container1Traits::width == Container2Traits::width, "Width different between Source and Destination" );
    static_assert( Container1Traits::height == Container2Traits::height, "Height different between Source and Destination" );
    static_assert( Container1Traits::depth == Container2Traits::depth, "Depth different between Source and Destination" );

    for ( std::size_t c = 0; c < ResultContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < ResultContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < ResultContainerTraits::raw_index0_size; ++a )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ResultContainerTwistType::width_pos_from( pos );
                std::size_t h = ResultContainerTwistType::height_pos_from( pos );
                std::size_t d = ResultContainerTwistType::depth_pos_from( pos );

                ValueTypeResult v = f( get( c1.content, w, h, d ), get( c2.content, w, h, d ), w, h, d );
                rawset( r.content, v, w, h, d );
            }
        }
    }
}

template <typename TwistType, std::size_t Width, std::size_t Height, std::size_t Depth, typename T>
auto make_block( T elem ) -> Block<T, TwistType, Width, Height, Depth>
{
    using Container = Block<T, TwistType, Width, Height, Depth>;
    using ContainerTraits = Traits<Container>;
    Container r;

    for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
            {
                rawset( r, elem, a, b, c );
            }
        }
    }

    return r;
}

template <typename T, typename TwistType, std::size_t Width, std::size_t Height, std::size_t Depth, typename Functor>
auto fill_block( Functor f ) -> Block<T, TwistType, Width, Height, Depth>
{
    using Container = Block<T, TwistType, Width, Height, Depth>;
    using ContainerTraits = Traits<Container>;
    using ContainerTwistType = typename Container::twist_type;
    Container r;

    for ( std::size_t c = 0; c < ContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < ContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < ContainerTraits::raw_index0_size; ++a )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = ContainerTwistType::width_pos_from( pos );
                std::size_t h = ContainerTwistType::height_pos_from( pos );
                std::size_t d = ContainerTwistType::depth_pos_from( pos );

                rawset( r, f( w, h, d ), a, b, c );
            }
        }
    }

    return r;
}

template <int TwistAmount, typename InputContainerType>
auto twist_block( InputContainerType const &input )
    -> Block<typename Traits<InputContainerType>::value_type,
             typename Twister<typename InputContainerType::twist_type, TwistAmount>::output_twist,
             Traits<InputContainerType>::width,
             Traits<InputContainerType>::height,
             Traits<InputContainerType>::depth>
{
    using InputContainerTwistType = typename InputContainerType::twist_type;
    using InputContainerTraits = Traits<InputContainerType>;
    using OutputContainerType = Block<typename Traits<InputContainerType>::value_type,
                                      typename Twister<typename InputContainerType::twist_type, TwistAmount>::output_twist,
                                      InputContainerTraits::width,
                                      InputContainerTraits::height,
                                      InputContainerTraits::depth>;
    using OutputContainerTraits = Traits<OutputContainerType>;
    using OutputContainerTwistType = typename OutputContainerType::twist_type;

    OutputContainerType r;

    std::cout << "raw_i0_size: " << OutputContainerTraits::raw_index0_size << std::endl;
    std::cout << "raw_i1_size: " << OutputContainerTraits::raw_index1_size << std::endl;
    std::cout << "raw_i2_size: " << OutputContainerTraits::raw_index2_size << std::endl;

    for ( std::size_t c = 0; c < OutputContainerTraits::raw_index2_size; ++c )
    {
        for ( std::size_t b = 0; b < OutputContainerTraits::raw_index1_size; ++b )
        {
            for ( std::size_t a = 0; a < OutputContainerTraits::raw_index0_size; ++a )
            {
                auto pos = std::make_tuple( a, b, c );
                std::size_t w = InputContainerTwistType::width_pos_from( pos );
                std::size_t h = InputContainerTwistType::height_pos_from( pos );
                std::size_t d = InputContainerTwistType::depth_pos_from( pos );

                rawset( r, get( input, w, h, d ), a, b, c );
            }
        }
    }

    return r;
}
}
<|endoftext|>


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

#pragma once

struct Options {
  // Debug mode
  bool debug;
  // Print messages to standard output
  bool print;
  // Use subband dedispersion
  bool subbandDedispersion;
  // Compact the triggered events in time and DM dimensions
  bool compactResults;
  // Threshold for triggering
  float threshold;
};

struct DeviceOptions {
  // OpenCL platform ID
  unsigned int platformID;
  // OpenCL device ID
  unsigned int deviceID;
  // OpenCL device name
  std::string deviceName;
  // Padding of OpenCL devices
  AstroData::paddingConf padding;
};

struct DataOptions {
  // Use LOFAR file as input
  bool dataLOFAR;
  // Use SIGPROC file as input
  bool dataSIGPROC;
  // Use PSRDADA buffer as input
  bool dataPSRDADA;
  // Limit the number of batches processed from a LOFAR file
  bool limit;
  // Size (in bytes) of the SIGPROC file header
  unsigned int headerSizeSIGPROC;
  // Name of the input file
  std::string dataFile;
  // Name of the LOFAR header file
  std::string headerFile;
  // Basename for the output files
  std::string outputFile;
  // Name of the file containing the zapped channels
  std::string channelsFile;
  // Name of the file containing the integration steps
  std::string integrationFile;
#ifdef HAVE_PSRDADA
  // PSRDADA buffer key
  key_t dadaKey;
#endif // HAVE_PSRDADA
};

struct GeneratorOptions {
  // Use random numbers in generated data
  bool random;
  // Width of random generated pulse
  unsigned int width;
  // DM of random generated pulse
  float DM;
};

struct HostMemory {
  // Input data
  std::vector<std::vector<std::vector<inputDataType> *> *> input;
  // Zapped channels
  std::vector<unsigned int> zappedChannels;
  // Integration steps
  std::set<unsigned int> integrationSteps;
  // Map to create synthesized beams
  std::vector<unsigned int> beamMapping;
  // Dispersed data
  std::vector<inputDataType> dispersedData;
  // Subbanded data
  std::vector<outputDataType> subbandedData;
  // Dedispersed data
  std::vector<outputDataType> dedispersedData;
  // Integrated data
  std::vector<outputDataType> integratedData;
  // SNR data
  std::vector<float> snrData;
  // Index of the sample with highest SNR value
  std::vector<unsigned int> snrSamples;
  // Shifts single step dedispersion
  std::vector<float> * shiftsSingleStep;
  // Shifts step one subbanding dedispersion
  std::vector<float> * shiftsStepOne;
  // Shifts step two subbanding dedispersion
  std::vector<float> * shiftsStepTwo;
#ifdef HAVE_PSRDADA
  // PSRDADA ring buffer
  dada_hdu_t * ringBuffer;
  // Input data
  std::vector<std::vector<inputDataType> *> inputDADA;
#endif // HAVE_PSRDADA
};

struct DeviceMemory {
  // Shifts single step dedispersion
  cl::Buffer shiftsSingleStep;
  // Shifts step one subbanding dedispersion
  cl::Buffer shiftsStepOne;
  // Shifts step two subbanding dedispersion
  cl::Buffer shiftsStepTwo;
  // Zapped channels
  cl::Buffer zappedChannels;
  // Map to create synthesized beams
  cl::Buffer beamMapping;
  // Dispersed dada
  cl::Buffer dispersedData;
  // Subbanded data
  cl::Buffer subbandedData;
  // Dedispersed data
  cl::Buffer dedispersedData;
  // Integrated data
  cl::Buffer integratedData;
  // SNR data
  cl::Buffer snrData;
  // Index of the sample with highest SNR value
  cl::Buffer snrSamples;
};

struct KernelConfigurations {
  // Configuration of single step dedispersion kernel
  Dedispersion::tunedDedispersionConf dedispersionParameters;
  // Configuration of subband dedispersion kernel, step one
  Dedispersion::tunedDedispersionConf dedispersionStepOneParameters;
  // Configuration of subband dedispersion kernel, step two
  Dedispersion::tunedDedispersionConf dedispersionStepTwoParameters;
  // Configuration of integration kernel
  Integration::tunedIntegrationConf integrationParameters;
  // Configuration of SNR kernel
  SNR::tunedSNRConf snrParameters;
};

struct Kernels {
  // Single step dedispersion kernel
  cl::Kernel * dedispersion;
  // Step one subbanding dedispersion kernel
  cl::Kernel * dedispersionStepOne;
  // Step two subbanding dedispersion kernel
  cl::Kernel * dedispersionStepTwo;
  // Integration kernels, one for each integration step
  std::vector<cl::Kernel *> integration;
  // SNR kernels, one for the original data and one for each integration step
  std::vector<cl::Kernel *> snr;
};

struct KernelRunTimeConfigurations {
  // Global NDrange for single step dedispersion
  cl::NDRange dedispersionSingleStepGlobal;
  // Local NDRange for single step dedispersion
  cl::NDRange dedispersionSingleStepLocal;
  // Global NDRange for subbanding dedispersion step one
  cl::NDRange dedispersionStepOneGlobal;
  // Local NDRange for subbanding dedispersion step one
  cl::NDRange dedispersionStepOneLocal;
  // Global NDRange for subbanding dedispersion step two
  cl::NDRange dedispersionStepTwoGlobal;
  // Local NDRange for subbanding dedispersion step two
  cl::NDRange dedispersionStepTwoLocal;
  // Global NDRange for integration
  std::vector<cl::NDRange> integrationGlobal;
  // Local NDRange for integration
  std::vector<cl::NDRange> integrationLocal;
  // Global NDRange for SNR
  std::vector<cl::NDRange> snrGlobal;
  // Local NDRange for SNR
  std::vector<cl::NDRange> snrLocal;
};

struct Timers {
  isa::utils::Timer inputLoad;
  isa::utils::Timer search;
  isa::utils::Timer inputHandling;
  isa::utils::Timer inputCopy;
  isa::utils::Timer dedispersionSingleStep;
  isa::utils::Timer dedispersionStepOne;
  isa::utils::Timer dedispersionStepTwo;
  isa::utils::Timer integration;
  isa::utils::Timer snr;
  isa::utils::Timer outputCopy;
  isa::utils::Timer trigger;
};

struct TriggeredEvent {
  unsigned int beam = 0;
  unsigned int sample = 0;
  unsigned int integration = 0;
  float DM = 0.0f;
  float SNR = 0.0f;
};

struct CompactedEvent : TriggeredEvent {
  unsigned int compactedIntegration = 1;
  unsigned int compactedDMs = 1;
};

using TriggeredEvents = std::vector<std::map<unsigned int, std::vector<TriggeredEvent>>>;
using CompactedEvents = std::vector<std::vector<CompactedEvent>>;

<commit_msg>Always specify that dedispersion means single step dedispersion.<commit_after>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

struct Options {
  // Debug mode
  bool debug;
  // Print messages to standard output
  bool print;
  // Use subband dedispersion
  bool subbandDedispersion;
  // Compact the triggered events in time and DM dimensions
  bool compactResults;
  // Threshold for triggering
  float threshold;
};

struct DeviceOptions {
  // OpenCL platform ID
  unsigned int platformID;
  // OpenCL device ID
  unsigned int deviceID;
  // OpenCL device name
  std::string deviceName;
  // Padding of OpenCL devices
  AstroData::paddingConf padding;
};

struct DataOptions {
  // Use LOFAR file as input
  bool dataLOFAR;
  // Use SIGPROC file as input
  bool dataSIGPROC;
  // Use PSRDADA buffer as input
  bool dataPSRDADA;
  // Limit the number of batches processed from a LOFAR file
  bool limit;
  // Size (in bytes) of the SIGPROC file header
  unsigned int headerSizeSIGPROC;
  // Name of the input file
  std::string dataFile;
  // Name of the LOFAR header file
  std::string headerFile;
  // Basename for the output files
  std::string outputFile;
  // Name of the file containing the zapped channels
  std::string channelsFile;
  // Name of the file containing the integration steps
  std::string integrationFile;
#ifdef HAVE_PSRDADA
  // PSRDADA buffer key
  key_t dadaKey;
#endif // HAVE_PSRDADA
};

struct GeneratorOptions {
  // Use random numbers in generated data
  bool random;
  // Width of random generated pulse
  unsigned int width;
  // DM of random generated pulse
  float DM;
};

struct HostMemory {
  // Input data
  std::vector<std::vector<std::vector<inputDataType> *> *> input;
  // Zapped channels
  std::vector<unsigned int> zappedChannels;
  // Integration steps
  std::set<unsigned int> integrationSteps;
  // Map to create synthesized beams
  std::vector<unsigned int> beamMapping;
  // Dispersed data
  std::vector<inputDataType> dispersedData;
  // Subbanded data
  std::vector<outputDataType> subbandedData;
  // Dedispersed data
  std::vector<outputDataType> dedispersedData;
  // Integrated data
  std::vector<outputDataType> integratedData;
  // SNR data
  std::vector<float> snrData;
  // Index of the sample with highest SNR value
  std::vector<unsigned int> snrSamples;
  // Shifts single step dedispersion
  std::vector<float> * shiftsSingleStep;
  // Shifts step one subbanding dedispersion
  std::vector<float> * shiftsStepOne;
  // Shifts step two subbanding dedispersion
  std::vector<float> * shiftsStepTwo;
#ifdef HAVE_PSRDADA
  // PSRDADA ring buffer
  dada_hdu_t * ringBuffer;
  // Input data
  std::vector<std::vector<inputDataType> *> inputDADA;
#endif // HAVE_PSRDADA
};

struct DeviceMemory {
  // Shifts single step dedispersion
  cl::Buffer shiftsSingleStep;
  // Shifts step one subbanding dedispersion
  cl::Buffer shiftsStepOne;
  // Shifts step two subbanding dedispersion
  cl::Buffer shiftsStepTwo;
  // Zapped channels
  cl::Buffer zappedChannels;
  // Map to create synthesized beams
  cl::Buffer beamMapping;
  // Dispersed dada
  cl::Buffer dispersedData;
  // Subbanded data
  cl::Buffer subbandedData;
  // Dedispersed data
  cl::Buffer dedispersedData;
  // Integrated data
  cl::Buffer integratedData;
  // SNR data
  cl::Buffer snrData;
  // Index of the sample with highest SNR value
  cl::Buffer snrSamples;
};

struct KernelConfigurations {
  // Configuration of single step dedispersion kernel
  Dedispersion::tunedDedispersionConf dedispersionParameters;
  // Configuration of subband dedispersion kernel, step one
  Dedispersion::tunedDedispersionConf dedispersionStepOneParameters;
  // Configuration of subband dedispersion kernel, step two
  Dedispersion::tunedDedispersionConf dedispersionStepTwoParameters;
  // Configuration of integration kernel
  Integration::tunedIntegrationConf integrationParameters;
  // Configuration of SNR kernel
  SNR::tunedSNRConf snrParameters;
};

struct Kernels {
  // Single step dedispersion kernel
  cl::Kernel * dedispersionSingleStep;
  // Step one subbanding dedispersion kernel
  cl::Kernel * dedispersionStepOne;
  // Step two subbanding dedispersion kernel
  cl::Kernel * dedispersionStepTwo;
  // Integration kernels, one for each integration step
  std::vector<cl::Kernel *> integration;
  // SNR kernels, one for the original data and one for each integration step
  std::vector<cl::Kernel *> snr;
};

struct KernelRunTimeConfigurations {
  // Global NDrange for single step dedispersion
  cl::NDRange dedispersionSingleStepGlobal;
  // Local NDRange for single step dedispersion
  cl::NDRange dedispersionSingleStepLocal;
  // Global NDRange for subbanding dedispersion step one
  cl::NDRange dedispersionStepOneGlobal;
  // Local NDRange for subbanding dedispersion step one
  cl::NDRange dedispersionStepOneLocal;
  // Global NDRange for subbanding dedispersion step two
  cl::NDRange dedispersionStepTwoGlobal;
  // Local NDRange for subbanding dedispersion step two
  cl::NDRange dedispersionStepTwoLocal;
  // Global NDRange for integration
  std::vector<cl::NDRange> integrationGlobal;
  // Local NDRange for integration
  std::vector<cl::NDRange> integrationLocal;
  // Global NDRange for SNR
  std::vector<cl::NDRange> snrGlobal;
  // Local NDRange for SNR
  std::vector<cl::NDRange> snrLocal;
};

struct Timers {
  isa::utils::Timer inputLoad;
  isa::utils::Timer search;
  isa::utils::Timer inputHandling;
  isa::utils::Timer inputCopy;
  isa::utils::Timer dedispersionSingleStep;
  isa::utils::Timer dedispersionStepOne;
  isa::utils::Timer dedispersionStepTwo;
  isa::utils::Timer integration;
  isa::utils::Timer snr;
  isa::utils::Timer outputCopy;
  isa::utils::Timer trigger;
};

struct TriggeredEvent {
  unsigned int beam = 0;
  unsigned int sample = 0;
  unsigned int integration = 0;
  float DM = 0.0f;
  float SNR = 0.0f;
};

struct CompactedEvent : TriggeredEvent {
  unsigned int compactedIntegration = 1;
  unsigned int compactedDMs = 1;
};

using TriggeredEvents = std::vector<std::map<unsigned int, std::vector<TriggeredEvent>>>;
using CompactedEvents = std::vector<std::vector<CompactedEvent>>;

<|endoftext|>


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

#include <string>

#include <utils.hpp>

#ifndef VECTOR_ADD_HPP
#define VECTOR_ADD_HPP

namespace isa {
namespace Benchmarks {

  std::string  * getVectorAddOpenCL(const unsigned int iterations, const unsigned int vector, const std::string & dataType);

// Implementations
std::string * getVectorAddOpenCL(const unsigned int iterations, const unsigned int vector, const std::string & dataType) {
  std::string * code = new std::string();

  if ( vector == 1 ) {
    *code = "__kernel void vectorAdd(const " + dataType + " * restrict const A, const " + dataType + " * restrict const B, " + dataType + " * C) {\n"
      + dataType + " a;\n"
      + dataType + " b;\n"
      + dataType + " c;\n"
      // Load
      "a = A[get_global_id(0)];\n"
      "b = B[get_global_id(0)];\n"
      // Compute
      "<%COMPUTE%>"
      // Store
      "C[get_global_id(0)] = c;\n"
      "}\n";
  } else {
    *code = "__kernel void vectorAdd(const " + dataType + " * restrict const A, const " + dataType + " * restrict const B, " + dataType + " * C) {\n"
      + dataType + isa::utils::toString(vector) + " a;\n"
      + dataType + isa::utils::toString(vector) + " b;\n"
      + dataType + isa::utils::toString(vector) + " c;\n"
      // Load
      "a = vload" + isa::utils::toString(vector) + "(0, &(A[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      "b = vload" + isa::utils::toString(vector) + "(0, &(B[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      // Compute
      "<%COMPUTE%>"
      // Store
      "vstore" + isa::utils::toString(vector) + "(c, 0, &(C[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      "}\n";
  }
  std::string computeTemplate = "c = a + b;\n";

  std::string * compute_s = new std::string();

  for ( unsigned int i = 0; i < iterations; i++ ) {
    compute_s->append(computeTemplate);
  }

  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);

  return code;
}

} // Benchmarks
} // isa

#endif

<commit_msg>Forgot the memory type.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>

#include <utils.hpp>

#ifndef VECTOR_ADD_HPP
#define VECTOR_ADD_HPP

namespace isa {
namespace Benchmarks {

  std::string  * getVectorAddOpenCL(const unsigned int iterations, const unsigned int vector, const std::string & dataType);

// Implementations
std::string * getVectorAddOpenCL(const unsigned int iterations, const unsigned int vector, const std::string & dataType) {
  std::string * code = new std::string();

  if ( vector == 1 ) {
    *code = "__kernel void vectorAdd(__global const " + dataType + " * restrict const A, __global const " + dataType + " * restrict const B, __global " + dataType + " * C) {\n"
      + dataType + " a;\n"
      + dataType + " b;\n"
      + dataType + " c;\n"
      // Load
      "a = A[get_global_id(0)];\n"
      "b = B[get_global_id(0)];\n"
      // Compute
      "<%COMPUTE%>"
      // Store
      "C[get_global_id(0)] = c;\n"
      "}\n";
  } else {
    *code = "__kernel void vectorAdd(__global const " + dataType + " * restrict const A, __global const " + dataType + " * restrict const B, __global " + dataType + " * C) {\n"
      + dataType + isa::utils::toString(vector) + " a;\n"
      + dataType + isa::utils::toString(vector) + " b;\n"
      + dataType + isa::utils::toString(vector) + " c;\n"
      // Load
      "a = vload" + isa::utils::toString(vector) + "(0, &(A[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      "b = vload" + isa::utils::toString(vector) + "(0, &(B[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      // Compute
      "<%COMPUTE%>"
      // Store
      "vstore" + isa::utils::toString(vector) + "(c, 0, &(C[get_global_id(0) * " + isa::utils::toString(vector) + "]));\n"
      "}\n";
  }
  std::string computeTemplate = "c = a + b;\n";

  std::string * compute_s = new std::string();

  for ( unsigned int i = 0; i < iterations; i++ ) {
    compute_s->append(computeTemplate);
  }

  code = isa::utils::replace(code, "<%COMPUTE%>", *compute_s, true);

  return code;
}

} // Benchmarks
} // isa

#endif

<|endoftext|>


<commit_before>

// not finished
// author: arvin@suse.de

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <wvstream.h>

#include "wvdialmon.h"

WvStream *pppd_log = NULL;	// to read messages of pppd

WvDialMon pppd_mon;

int main( int argc, char ** argv )
{
  int argc_ppp = 0;
  char *argv_ppp[ argc+10 ];

  argv_ppp[argc_ppp++] = "/usr/sbin/pppd";

  for( int i = 1; i < argc; i++ )
    argv_ppp[argc_ppp++] = argv[i];

  // open a pipe to access the messages of pppd
  int pppd_msgfd[2];
  if( pipe( pppd_msgfd ) == -1 ) {
    fprintf( stderr, "pipe failed: %s\n", strerror(errno) );
    exit( EXIT_FAILURE );
  }

  char buffer[20];
  sprintf( buffer, "%d", pppd_msgfd[1] );
  argv_ppp[argc_ppp++] = "logfd";
  argv_ppp[argc_ppp++] = buffer;

  pppd_log = new WvStream( pppd_msgfd[0] );

  pppd_mon.setconnectmsg( "Connected..." );

  /*
  for( int i = 0; i < argc_ppp; i++ )
    printf( "%s\n", argv_ppp[i] );
  */

  // fork and exec pppd
  pid_t pid = fork();

  if( pid == (pid_t) 0 ) {	// we are the child
    argv_ppp[argc_ppp] = NULL;
    execv( argv_ppp[0], argv_ppp );
    fprintf( stderr, "exec failed: %s\n", strerror(errno) );
    exit( EXIT_FAILURE );
  }

  if( pid < (pid_t) 0 ) {	// the fork failed
    fprintf( stderr, "error: can't fork child process\n" );
    exit( EXIT_FAILURE );
  }

  /*
  ppp_pipe = new WvPipe( argv_ppp[0], argv_ppp, false, false, false );
  */

  // install signals

  for( ;; ) {

    // see if pppd is still alive

    // now watch for messages and output to stdout

    if( pppd_log != NULL && pppd_log->isok() ) {

      char *line;

      do {

	line = pppd_log->getline( 100 );
	if( line != NULL ) {
	  char *buffer1 = pppd_mon.analyse_line( line );
	  if( buffer1 != NULL && buffer1[0] != '\0' ) {
	    char buffer2[ strlen( buffer1 ) + 10 ];
	    sprintf( buffer2, "pppd: %s", buffer1 );
	    fprintf( stdout, "%s", buffer2 );
	  }
	}
      } while( line != NULL );

    }

  }

  exit( EXIT_SUCCESS );
}
<commit_msg>Made wvfork() even safer. Also minor changes to WvPrintService.<commit_after>

// not finished
// author: arvin@suse.de

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <wvstream.h>

#include "wvdialmon.h"
#include "wvfork.h"

WvStream *pppd_log = NULL;	// to read messages of pppd

WvDialMon pppd_mon;

int main( int argc, char ** argv )
{
  int argc_ppp = 0;
  char *argv_ppp[ argc+10 ];

  argv_ppp[argc_ppp++] = "/usr/sbin/pppd";

  for( int i = 1; i < argc; i++ )
    argv_ppp[argc_ppp++] = argv[i];

  // open a pipe to access the messages of pppd
  int pppd_msgfd[2];
  if( pipe( pppd_msgfd ) == -1 ) {
    fprintf( stderr, "pipe failed: %s\n", strerror(errno) );
    exit( EXIT_FAILURE );
  }

  char buffer[20];
  sprintf( buffer, "%d", pppd_msgfd[1] );
  argv_ppp[argc_ppp++] = "logfd";
  argv_ppp[argc_ppp++] = buffer;

  pppd_log = new WvStream( pppd_msgfd[0] );

  pppd_mon.setconnectmsg( "Connected..." );

  /*
  for( int i = 0; i < argc_ppp; i++ )
    printf( "%s\n", argv_ppp[i] );
  */

  // fork and exec pppd
  pid_t pid = wvfork();

  if( pid == (pid_t) 0 ) {	// we are the child
    argv_ppp[argc_ppp] = NULL;
    execv( argv_ppp[0], argv_ppp );
    fprintf( stderr, "exec failed: %s\n", strerror(errno) );
    exit( EXIT_FAILURE );
  }

  if( pid < (pid_t) 0 ) {	// the fork failed
    fprintf( stderr, "error: can't fork child process\n" );
    exit( EXIT_FAILURE );
  }

  /*
  ppp_pipe = new WvPipe( argv_ppp[0], argv_ppp, false, false, false );
  */

  // install signals

  for( ;; ) {

    // see if pppd is still alive

    // now watch for messages and output to stdout

    if( pppd_log != NULL && pppd_log->isok() ) {

      char *line;

      do {

	line = pppd_log->getline( 100 );
	if( line != NULL ) {
	  char *buffer1 = pppd_mon.analyse_line( line );
	  if( buffer1 != NULL && buffer1[0] != '\0' ) {
	    char buffer2[ strlen( buffer1 ) + 10 ];
	    sprintf( buffer2, "pppd: %s", buffer1 );
	    fprintf( stdout, "%s", buffer2 );
	  }
	}
      } while( line != NULL );

    }

  }

  exit( EXIT_SUCCESS );
}
<|endoftext|>


<commit_before>#include "Hash.hpp"
#include "collections/Collection.hpp"
#include "collections/Set.hpp"
#include "collections/Seq.hpp"
#include "collections/Sorted.hpp"
#include "collections/Map.hpp"
#include "collections/IntMap.hpp"
#include "collections/StrMap.hpp"
#include "collections/Vector.hpp"
#include "collections/RealVector.hpp"
#include "collections/MultiIndex.hpp"
#include "collections/VMap.hpp"
#include "collections/SortedMap.hpp"
#include "collections/SortedSet.hpp"
#include "collections/MapE.hpp"
#include "collections/SortedMapE.hpp"
#include "HashCollections.hpp"
<commit_msg>Added IntVector to superheader<commit_after>#include "Hash.hpp"
#include "collections/Collection.hpp"
#include "collections/Set.hpp"
#include "collections/Seq.hpp"
#include "collections/Sorted.hpp"
#include "collections/Map.hpp"
#include "collections/IntMap.hpp"
#include "collections/StrMap.hpp"
#include "collections/Vector.hpp"
#include "collections/IntVector.hpp"
#include "collections/RealVector.hpp"
#include "collections/MultiIndex.hpp"
#include "collections/VMap.hpp"
#include "collections/SortedMap.hpp"
#include "collections/SortedSet.hpp"
#include "collections/MapE.hpp"
#include "collections/SortedMapE.hpp"
#include "HashCollections.hpp"
<|endoftext|>


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

#include "TextureAtlasFilter.hpp"
#include "FreeImage.hpp"
#include <nvtt/nvtt.h>

namespace Sirikata {
namespace Mesh {

namespace {
struct Rect;
struct Region;

// Rect is used to define the size in pixels of a rectangular region
struct Rect {
    int32 min_x;
    int32 min_y;
    int32 max_x;
    int32 max_y;

    int32 width() const { return max_x - min_x + 1; }
    int32 height() const { return max_y - min_y + 1; }
    int32 x() const { return min_x; }
    int32 y() const { return min_y; }

    static Rect fromBaseOffset(int32 _min_x, int32 _min_y, int32 _width, int32 _height) {
        Rect ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _min_x + _width - 1;
        ret.max_y = _min_y + _height - 1;
        return ret;
    }
    static Rect fromBounds(int32 _min_x, int32 _min_y, int32 _max_x, int32 _max_y) {
        Rect ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _max_x;
        ret.max_y = _max_y;
        return ret;
    }

    Region region(const Rect& subrect);
    Rect region(const Region& subreg);
};

// Region is used to define a region of a Rect. It's values are always in the
// range 0 to 1
struct Region {
    float min_x;
    float min_y;
    float max_x;
    float max_y;

    static Region fromBaseOffset(float _min_x, float _min_y, float _width, float _height) {
        Region ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _min_x + _width;
        ret.max_y = _min_y + _height;
        return ret;
    }
    static Region fromBounds(float _min_x, float _min_y, float _max_x, float _max_y) {
        Region ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _max_x;
        ret.max_y = _max_y;
        return ret;
    }

    float width() const { return max_x - min_x; }
    float height() const { return max_y - min_y; }
    float x() const { return min_x; }
    float y() const { return min_y; }

    // Convert a (u,v) in this region's coordinates (u and v between 0 and 1) to
    // parent coordinates.
    void convert(float u, float v, float* u_out, float* v_out) {
        float u_o = min_x + u * width();
        float v_o = min_y + v * height();
        *u_out = min_x + u * width();
        *v_out = min_y + v * height();
    }
};

Region Rect::region(const Rect& subrect) {
    return Region::fromBounds(
        (subrect.min_x/(float)width()), (subrect.min_y/(float)height()),
        ((subrect.max_x+1)/(float)width()), ((subrect.max_y+1)/(float)height())
    );
}

Rect Rect::region(const Region& subreg) {
    return Rect::fromBaseOffset(
        (int32)(subreg.min_x * width()), (int32)(subreg.min_y * height()),
        (int32)(subreg.width() * width()), (int32)(subreg.height() * height())
    );
}

// Track some information about the texture that we need as we process it.
struct TexInfo {
    String url;
    Rect orig_size;
    FIBITMAP* image;
    Region atlas_region;
};

// Compute a hash value for texture sets in a Meshdata.
int TextureSetHash(MeshdataPtr md, int sub_mesh_idx, int tex_set_idx) {
    return (tex_set_idx * md->geometry.size()) + sub_mesh_idx;
}

} // namespace

TextureAtlasFilter::TextureAtlasFilter(const String& args) {
}

MeshdataPtr TextureAtlasFilter::apply(MeshdataPtr md) {
    // Currently we use a very simple approach: take all textures and
    // tile them into equal size regions, tiling in 2D.

    typedef std::map<String, TexInfo> TexInfoMap;
    TexInfoMap tex_info;

    // We only know how to handle local files
    if (md->uri.size() < 7 || md->uri.substr(0, 7) != "file://") return md;
    String uri_dir = md->uri.substr(7);
    size_t slash_pos = uri_dir.rfind("/");
    if (slash_pos == std::string::npos || slash_pos == uri_dir.size()-1)
        uri_dir = "./";
    else
        uri_dir = uri_dir.substr(0, slash_pos+1);

    // If the same texUVs in a SubMeshGeometry are referenced by instances with
    // different materials, then this code doesn't know how to handle them (we'd
    // probably have to duplicate texUVs, and in doing so, decide whether the
    // memory increase is worth it).
    std::map<int, int> tex_set_materials; // Unique tex coord hash -> material
                                          // idx
    {
        // We need to run through all instances and look for conflicts. A
        // texture coordinate set is uniquely identified by SubMeshGeometry
        // index and the index in SubMeshGeometry::texUVs. Since we know the
        // number of SubMeshGeometries, we use
        //   (tex coord index * num sub mesh geometries) + sub mesh geo index
        // to generate a unique index. Many instances may map to one of these
        // and we just want to check that no two instances use different textures
        Meshdata::GeometryInstanceIterator geo_inst_it = md->getGeometryInstanceIterator();
        uint32 geo_inst_idx;
        Matrix4x4f pos_xform;
        bool conflicts = false;
        while( geo_inst_it.next(&geo_inst_idx, &pos_xform) ) {
            GeometryInstance& geo_inst = md->instances[geo_inst_idx];
            int sub_mesh_idx = geo_inst.geometryIndex;
            for(GeometryInstance::MaterialBindingMap::iterator mat_it = geo_inst.materialBindingMap.begin(); mat_it != geo_inst.materialBindingMap.end(); mat_it++) {
                int texset_idx = mat_it->first;
                int mat_idx = mat_it->second;

                int tex_set_hash = TextureSetHash(md, sub_mesh_idx, texset_idx);
                if (tex_set_materials.find(tex_set_hash) != tex_set_materials.end() &&
                    tex_set_materials[tex_set_hash] != mat_idx)
                {
                    // Conflict, can't handle, pass on without any processing
                    SILOG(textureatlas, error, "[TEXTUREATLAS] Found two instances using different materials referencing the same geometry -- can't safely generate atlas.");
                    return md;
                }
                tex_set_materials[tex_set_hash] = mat_idx;
            }
        }
    }

    // First compute some stats.
    for(uint32 tex_i = 0; tex_i < md->textures.size(); tex_i++) {
        String tex_url = md->textures[tex_i];
        String texfile = uri_dir + tex_url;

        tex_info[tex_url] = TexInfo();
        tex_info[tex_url].url = tex_url;

        // Load the data from the original file
        FIBITMAP* input_image = GenericLoader(texfile.c_str(), 0);
        if (input_image == NULL) { // Couldn't figure out how to load it
            tex_info[tex_url].image = NULL;
            continue;
        }

        // Make sure we get the data in BGRA 8UB and properly packed
        FIBITMAP* input_image_32 = FreeImage_ConvertTo32Bits(input_image);
        FreeImage_Unload(input_image);
        tex_info[tex_url].image = input_image_32;

        int32 width = FreeImage_GetWidth(input_image_32);
        int32 height = FreeImage_GetHeight(input_image_32);

        tex_info[tex_url].orig_size = Rect::fromBaseOffset(0, 0, width, height);
    }

    // Select the block size and layout, create target image
    int ntextures = tex_info.size();
    int ntextures_side = (int)(sqrtf((float)ntextures) + 1.f);

    // FIXME
    uint32 atlas_element_width = 256, atlas_element_height = 256;

    uint32 atlas_width = ntextures_side * atlas_element_width,
        atlas_height = ntextures_side * atlas_element_height;

    FIBITMAP* atlas = FreeImage_Allocate(atlas_width, atlas_height, 32);

    // Scale images to desired size, copy data into the target image
    int idx = 0;
    Rect atlas_rect = Rect::fromBaseOffset(0, 0, atlas_width, atlas_height);
    for(TexInfoMap::iterator tex_it = tex_info.begin(); tex_it != tex_info.end(); tex_it++) {
        TexInfo& tex = tex_it->second;
        // Resize
        uint32 new_width = atlas_element_width, new_height = atlas_element_height; // FIXME
        FIBITMAP* resized = FreeImage_Rescale(tex.image, new_width, new_height, FILTER_LANCZOS3);
        // Copy into place
        int x_idx = idx % ntextures_side;
        int y_idx = idx / ntextures_side;

        Rect tex_sub_rect = Rect::fromBaseOffset(
            x_idx * atlas_element_width, y_idx * atlas_element_height,
            atlas_element_width, atlas_element_height
        );

        tex.atlas_region = atlas_rect.region(tex_sub_rect);
        FreeImage_Paste(atlas, resized, tex_sub_rect.min_x, tex_sub_rect.min_y, 256);

        FreeImage_Unload(resized);
        FreeImage_Unload(tex_it->second.image);
        tex_it->second.image = NULL;

        idx++;
    }

    // Generate the texture atlas
    String atlas_url = uri_dir + "atlas.png";
    FreeImage_Save(FIF_PNG, atlas, atlas_url.c_str());
    FreeImage_Unload(atlas);

    // Now we need to run through and fix up texture references and texture
    // coordinates
    // 1. Replace old textures with new one
    TextureList orig_texture_list = md->textures;
    md->textures.clear();
    md->textures.push_back(atlas_url);
    // 2. Update texture coordinates. Since we've stored texture set hash ->
    // material indices, we can easily work from this to quickly iterate over
    // items and transform the coordinates.
    for(uint32 geo_idx = 0; geo_idx < md->geometry.size(); geo_idx++) {
        // Each submesh has texUVs that need updating
        SubMeshGeometry& submesh = md->geometry[geo_idx];

        // We need to modify each texture coordinate set in this geometry. We
        // put this as the outer loop so we replace the entire uv set with a
        // new, filtered copy so we make sure we don't double-transform any of
        // the coordinates.
        for(int tex_set_idx = 0; tex_set_idx < submesh.texUVs.size(); tex_set_idx++) {
            SubMeshGeometry::TextureSet& tex_set = submesh.texUVs[tex_set_idx];
            std::vector<float> new_uvs = tex_set.uvs;

            // Each prim defines a material mapping, so we need to split the
            // texture coordinates up by prim.
            for(int prim_idx = 0; prim_idx < submesh.primitives.size(); prim_idx++) {
                SubMeshGeometry::Primitive& prim = submesh.primitives[prim_idx];
                int mat_id = prim.materialId;

                int tex_set_hash = TextureSetHash(md, geo_idx, mat_id);
                // We stored up the correct material index to find it in the
                // Meshdata in the tex_set_materials when we were sanity checking
                // that there were no conflicts.
                int mat_idx = tex_set_materials[tex_set_hash];

                // Finally, having extracted all the material mapping info, we
                // can loop through referenced indices and transform them.
                MaterialEffectInfo& mat = md->materials[mat_idx];

                // Do transformation for each texture that has a URI. Some may
                // be duplicates, some may not have a URI, but doing them all
                // ensures we catch everything.
                for(int mat_tex_idx = 0; mat_tex_idx < mat.textures.size(); mat_tex_idx++) {
                    MaterialEffectInfo::Texture& real_tex = mat.textures[mat_tex_idx];
                    if (tex_info.find(real_tex.uri) == tex_info.end()) continue;
                    TexInfo& final_tex_info = tex_info[real_tex.uri];

                    for(int index_idx = 0; index_idx < prim.indices.size(); index_idx++) {
                        int index = prim.indices[index_idx];
                        float new_u, new_v;
                        assert(tex_set.stride >= 2);
                        final_tex_info.atlas_region.convert(
                            tex_set.uvs[index * tex_set.stride],
                            tex_set.uvs[index * tex_set.stride + 1],
                            &new_u, &new_v);
                        new_uvs[ index * tex_set.stride ] = new_u;
                        new_uvs[ index * tex_set.stride + 1 ] = new_v;
                    }
                }
            }
            tex_set.uvs = new_uvs;
        }
    }
    // 3. Replace references in materials to old URI's with new one
    for(MaterialEffectInfoList::iterator mat_it = md->materials.begin(); mat_it != md->materials.end(); mat_it++) {
        MaterialEffectInfo& mat_info = *mat_it;
        for(MaterialEffectInfo::TextureList::iterator tex_it = mat_info.textures.begin(); tex_it != mat_info.textures.end(); tex_it++) {
            tex_it->uri = atlas_url;
        }
    }

    return md;
}

FilterDataPtr TextureAtlasFilter::apply(FilterDataPtr input) {
    using namespace nvtt;

    InitFreeImage();

    MutableFilterDataPtr output(new FilterData());
    for(FilterData::const_iterator mesh_it = input->begin(); mesh_it != input->end(); mesh_it++) {
        MeshdataPtr mesh = *mesh_it;
        MeshdataPtr ta_mesh = apply(mesh);
        output->push_back(ta_mesh);
    }
    return output;
}

} // namespace Mesh
} // namespace Sirikata
<commit_msg>In texture atlasing, only replace texture URLs if there already was one. Some 'textures' are just plain color materials and should not have a texture added to them.<commit_after>/*  Sirikata
 *  TextureAtlasFilter.cpp
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "TextureAtlasFilter.hpp"
#include "FreeImage.hpp"
#include <nvtt/nvtt.h>

namespace Sirikata {
namespace Mesh {

namespace {
struct Rect;
struct Region;

// Rect is used to define the size in pixels of a rectangular region
struct Rect {
    int32 min_x;
    int32 min_y;
    int32 max_x;
    int32 max_y;

    int32 width() const { return max_x - min_x + 1; }
    int32 height() const { return max_y - min_y + 1; }
    int32 x() const { return min_x; }
    int32 y() const { return min_y; }

    static Rect fromBaseOffset(int32 _min_x, int32 _min_y, int32 _width, int32 _height) {
        Rect ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _min_x + _width - 1;
        ret.max_y = _min_y + _height - 1;
        return ret;
    }
    static Rect fromBounds(int32 _min_x, int32 _min_y, int32 _max_x, int32 _max_y) {
        Rect ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _max_x;
        ret.max_y = _max_y;
        return ret;
    }

    Region region(const Rect& subrect);
    Rect region(const Region& subreg);
};

// Region is used to define a region of a Rect. It's values are always in the
// range 0 to 1
struct Region {
    float min_x;
    float min_y;
    float max_x;
    float max_y;

    static Region fromBaseOffset(float _min_x, float _min_y, float _width, float _height) {
        Region ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _min_x + _width;
        ret.max_y = _min_y + _height;
        return ret;
    }
    static Region fromBounds(float _min_x, float _min_y, float _max_x, float _max_y) {
        Region ret;
        ret.min_x = _min_x;
        ret.min_y = _min_y;
        ret.max_x = _max_x;
        ret.max_y = _max_y;
        return ret;
    }

    float width() const { return max_x - min_x; }
    float height() const { return max_y - min_y; }
    float x() const { return min_x; }
    float y() const { return min_y; }

    // Convert a (u,v) in this region's coordinates (u and v between 0 and 1) to
    // parent coordinates.
    void convert(float u, float v, float* u_out, float* v_out) {
        float u_o = min_x + u * width();
        float v_o = min_y + v * height();
        *u_out = min_x + u * width();
        *v_out = min_y + v * height();
    }
};

Region Rect::region(const Rect& subrect) {
    return Region::fromBounds(
        (subrect.min_x/(float)width()), (subrect.min_y/(float)height()),
        ((subrect.max_x+1)/(float)width()), ((subrect.max_y+1)/(float)height())
    );
}

Rect Rect::region(const Region& subreg) {
    return Rect::fromBaseOffset(
        (int32)(subreg.min_x * width()), (int32)(subreg.min_y * height()),
        (int32)(subreg.width() * width()), (int32)(subreg.height() * height())
    );
}

// Track some information about the texture that we need as we process it.
struct TexInfo {
    String url;
    Rect orig_size;
    FIBITMAP* image;
    Region atlas_region;
};

// Compute a hash value for texture sets in a Meshdata.
int TextureSetHash(MeshdataPtr md, int sub_mesh_idx, int tex_set_idx) {
    return (tex_set_idx * md->geometry.size()) + sub_mesh_idx;
}

} // namespace

TextureAtlasFilter::TextureAtlasFilter(const String& args) {
}

MeshdataPtr TextureAtlasFilter::apply(MeshdataPtr md) {
    // Currently we use a very simple approach: take all textures and
    // tile them into equal size regions, tiling in 2D.

    typedef std::map<String, TexInfo> TexInfoMap;
    TexInfoMap tex_info;

    // We only know how to handle local files
    if (md->uri.size() < 7 || md->uri.substr(0, 7) != "file://") return md;
    String uri_dir = md->uri.substr(7);
    size_t slash_pos = uri_dir.rfind("/");
    if (slash_pos == std::string::npos || slash_pos == uri_dir.size()-1)
        uri_dir = "./";
    else
        uri_dir = uri_dir.substr(0, slash_pos+1);

    // If the same texUVs in a SubMeshGeometry are referenced by instances with
    // different materials, then this code doesn't know how to handle them (we'd
    // probably have to duplicate texUVs, and in doing so, decide whether the
    // memory increase is worth it).
    std::map<int, int> tex_set_materials; // Unique tex coord hash -> material
                                          // idx
    {
        // We need to run through all instances and look for conflicts. A
        // texture coordinate set is uniquely identified by SubMeshGeometry
        // index and the index in SubMeshGeometry::texUVs. Since we know the
        // number of SubMeshGeometries, we use
        //   (tex coord index * num sub mesh geometries) + sub mesh geo index
        // to generate a unique index. Many instances may map to one of these
        // and we just want to check that no two instances use different textures
        Meshdata::GeometryInstanceIterator geo_inst_it = md->getGeometryInstanceIterator();
        uint32 geo_inst_idx;
        Matrix4x4f pos_xform;
        bool conflicts = false;
        while( geo_inst_it.next(&geo_inst_idx, &pos_xform) ) {
            GeometryInstance& geo_inst = md->instances[geo_inst_idx];
            int sub_mesh_idx = geo_inst.geometryIndex;
            for(GeometryInstance::MaterialBindingMap::iterator mat_it = geo_inst.materialBindingMap.begin(); mat_it != geo_inst.materialBindingMap.end(); mat_it++) {
                int texset_idx = mat_it->first;
                int mat_idx = mat_it->second;

                int tex_set_hash = TextureSetHash(md, sub_mesh_idx, texset_idx);
                if (tex_set_materials.find(tex_set_hash) != tex_set_materials.end() &&
                    tex_set_materials[tex_set_hash] != mat_idx)
                {
                    // Conflict, can't handle, pass on without any processing
                    SILOG(textureatlas, error, "[TEXTUREATLAS] Found two instances using different materials referencing the same geometry -- can't safely generate atlas.");
                    return md;
                }
                tex_set_materials[tex_set_hash] = mat_idx;
            }
        }
    }

    // First compute some stats.
    for(uint32 tex_i = 0; tex_i < md->textures.size(); tex_i++) {
        String tex_url = md->textures[tex_i];
        String texfile = uri_dir + tex_url;

        tex_info[tex_url] = TexInfo();
        tex_info[tex_url].url = tex_url;

        // Load the data from the original file
        FIBITMAP* input_image = GenericLoader(texfile.c_str(), 0);
        if (input_image == NULL) { // Couldn't figure out how to load it
            tex_info[tex_url].image = NULL;
            continue;
        }

        // Make sure we get the data in BGRA 8UB and properly packed
        FIBITMAP* input_image_32 = FreeImage_ConvertTo32Bits(input_image);
        FreeImage_Unload(input_image);
        tex_info[tex_url].image = input_image_32;

        int32 width = FreeImage_GetWidth(input_image_32);
        int32 height = FreeImage_GetHeight(input_image_32);

        tex_info[tex_url].orig_size = Rect::fromBaseOffset(0, 0, width, height);
    }

    // Select the block size and layout, create target image
    int ntextures = tex_info.size();
    int ntextures_side = (int)(sqrtf((float)ntextures) + 1.f);

    // FIXME
    uint32 atlas_element_width = 256, atlas_element_height = 256;

    uint32 atlas_width = ntextures_side * atlas_element_width,
        atlas_height = ntextures_side * atlas_element_height;

    FIBITMAP* atlas = FreeImage_Allocate(atlas_width, atlas_height, 32);

    // Scale images to desired size, copy data into the target image
    int idx = 0;
    Rect atlas_rect = Rect::fromBaseOffset(0, 0, atlas_width, atlas_height);
    for(TexInfoMap::iterator tex_it = tex_info.begin(); tex_it != tex_info.end(); tex_it++) {
        TexInfo& tex = tex_it->second;
        // Resize
        uint32 new_width = atlas_element_width, new_height = atlas_element_height; // FIXME
        FIBITMAP* resized = FreeImage_Rescale(tex.image, new_width, new_height, FILTER_LANCZOS3);
        // Copy into place
        int x_idx = idx % ntextures_side;
        int y_idx = idx / ntextures_side;

        Rect tex_sub_rect = Rect::fromBaseOffset(
            x_idx * atlas_element_width, y_idx * atlas_element_height,
            atlas_element_width, atlas_element_height
        );

        tex.atlas_region = atlas_rect.region(tex_sub_rect);
        FreeImage_Paste(atlas, resized, tex_sub_rect.min_x, tex_sub_rect.min_y, 256);

        FreeImage_Unload(resized);
        FreeImage_Unload(tex_it->second.image);
        tex_it->second.image = NULL;

        idx++;
    }

    // Generate the texture atlas
    String atlas_url = uri_dir + "atlas.png";
    FreeImage_Save(FIF_PNG, atlas, atlas_url.c_str());
    FreeImage_Unload(atlas);

    // Now we need to run through and fix up texture references and texture
    // coordinates
    // 1. Replace old textures with new one
    TextureList orig_texture_list = md->textures;
    md->textures.clear();
    md->textures.push_back(atlas_url);
    // 2. Update texture coordinates. Since we've stored texture set hash ->
    // material indices, we can easily work from this to quickly iterate over
    // items and transform the coordinates.
    for(uint32 geo_idx = 0; geo_idx < md->geometry.size(); geo_idx++) {
        // Each submesh has texUVs that need updating
        SubMeshGeometry& submesh = md->geometry[geo_idx];

        // We need to modify each texture coordinate set in this geometry. We
        // put this as the outer loop so we replace the entire uv set with a
        // new, filtered copy so we make sure we don't double-transform any of
        // the coordinates.
        for(int tex_set_idx = 0; tex_set_idx < submesh.texUVs.size(); tex_set_idx++) {
            SubMeshGeometry::TextureSet& tex_set = submesh.texUVs[tex_set_idx];
            std::vector<float> new_uvs = tex_set.uvs;

            // Each prim defines a material mapping, so we need to split the
            // texture coordinates up by prim.
            for(int prim_idx = 0; prim_idx < submesh.primitives.size(); prim_idx++) {
                SubMeshGeometry::Primitive& prim = submesh.primitives[prim_idx];
                int mat_id = prim.materialId;

                int tex_set_hash = TextureSetHash(md, geo_idx, mat_id);
                // We stored up the correct material index to find it in the
                // Meshdata in the tex_set_materials when we were sanity checking
                // that there were no conflicts.
                int mat_idx = tex_set_materials[tex_set_hash];

                // Finally, having extracted all the material mapping info, we
                // can loop through referenced indices and transform them.
                MaterialEffectInfo& mat = md->materials[mat_idx];

                // Do transformation for each texture that has a URI. Some may
                // be duplicates, some may not have a URI, but doing them all
                // ensures we catch everything.
                for(int mat_tex_idx = 0; mat_tex_idx < mat.textures.size(); mat_tex_idx++) {
                    MaterialEffectInfo::Texture& real_tex = mat.textures[mat_tex_idx];
                    if (tex_info.find(real_tex.uri) == tex_info.end()) continue;
                    TexInfo& final_tex_info = tex_info[real_tex.uri];

                    for(int index_idx = 0; index_idx < prim.indices.size(); index_idx++) {
                        int index = prim.indices[index_idx];
                        float new_u, new_v;
                        assert(tex_set.stride >= 2);
                        final_tex_info.atlas_region.convert(
                            tex_set.uvs[index * tex_set.stride],
                            tex_set.uvs[index * tex_set.stride + 1],
                            &new_u, &new_v);
                        new_uvs[ index * tex_set.stride ] = new_u;
                        new_uvs[ index * tex_set.stride + 1 ] = new_v;
                    }
                }
            }
            tex_set.uvs = new_uvs;
        }
    }
    // 3. Replace references in materials to old URI's with new one
    for(MaterialEffectInfoList::iterator mat_it = md->materials.begin(); mat_it != md->materials.end(); mat_it++) {
        MaterialEffectInfo& mat_info = *mat_it;
        for(MaterialEffectInfo::TextureList::iterator tex_it = mat_info.textures.begin(); tex_it != mat_info.textures.end(); tex_it++) {
            if (!tex_it->uri.empty())
                tex_it->uri = atlas_url;
        }
    }

    return md;
}

FilterDataPtr TextureAtlasFilter::apply(FilterDataPtr input) {
    using namespace nvtt;

    InitFreeImage();

    MutableFilterDataPtr output(new FilterData());
    for(FilterData::const_iterator mesh_it = input->begin(); mesh_it != input->end(); mesh_it++) {
        MeshdataPtr mesh = *mesh_it;
        MeshdataPtr ta_mesh = apply(mesh);
        output->push_back(ta_mesh);
    }
    return output;
}

} // namespace Mesh
} // namespace Sirikata
<|endoftext|>