<commit_before>/*
Copyright (c) 2006-2008 Advanced Micro Devices, Inc. All Rights Reserved.
This software is subject to the Apache v2.0 License.
*/

/************************************************************/
#include "buildnum.h"
#include "fwVideo.h"
#include "FwSharedCode.h"
#include "FwSharedCode_SSE2.h"

#include <iostream>

using namespace OPT_LEVEL;

extern const unsigned int NUM_COLS;
extern const unsigned int NUM_ELEMS;

namespace OPT_LEVEL
{

FwStatus SYS_INLINE quantInvIntra_MPEG2(Fw16s *pSrcDst, int &QP, Fw16s *pQPMatrix)
{
	if(FW_REF::PtrNotOK(pSrcDst, pQPMatrix))return fwStsNullPtrErr;

	switch(Dispatch::Type<DT_SSE2>())
	{
	case DT_SSE3:
	case DT_SSE2:
		{
			const bool bSrcDstIsAligned = FW_REF::IsAligned(pSrcDst,16);
			const bool bQPMatrixIsAligned = FW_REF::IsAligned(pQPMatrix,16);
			__m128i qpConst = _mm_set_epi16(CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP));
			__m128i row;
			__m128i qpRow;
            XMM128 mismatch;
            __m128i mask_negative;
            __m128i zero = _mm_setzero_si128();
            mismatch.i = _mm_setzero_si128();
            Fw16s src1 = pSrcDst[0];

            mismatch.s16[0] = pSrcDst[0] ^ 1;
            pSrcDst[0]= 0;

			for(unsigned int I = 0; I < NUM_COLS; I++)
			{
				row = (bSrcDstIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pSrcDst) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pSrcDst) + I);
				qpRow = (bQPMatrixIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I);

                mask_negative = _mm_cmplt_epi16(row, zero);

                __m128i negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

				__m128i low = _mm_mullo_epi16(row, qpRow);
				__m128i high = _mm_mulhi_epi16(row, qpRow);
				row = _mm_unpacklo_epi16(low, high);
				__m128i tmpHigh = _mm_unpackhi_epi16(low, high);
				FW_SSE2::pack32STo16S(row, tmpHigh);

				low = _mm_mullo_epi16(row, qpConst);
				high = _mm_mulhi_epi16(row, qpConst);
				row = _mm_unpacklo_epi16(low, high);
				tmpHigh = _mm_unpackhi_epi16(low, high);
                FW_SSE2::pack32STo16S(row, tmpHigh);

                row = _mm_srli_epi16(row, 4);
                negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                mismatch.i = _mm_xor_si128(row,mismatch.i);

				__m128i* p128i = reinterpret_cast<__m128i*>(pSrcDst);
				if(bSrcDstIsAligned)
				{
					_mm_store_si128(&p128i[I], row);
				}
				else
				{
					_mm_storeu_si128(&p128i[I], row);
				}
			}

			mismatch.s16[0] ^= mismatch.s16[1] ^  mismatch.s16[2] ^  mismatch.s16[3] ^ mismatch.s16[4];
			pSrcDst[63] ^= (mismatch.s16[0] ^ mismatch.s16[5] ^  mismatch.s16[6] ^  mismatch.s16[7]) & 1;
            pSrcDst[0] = src1;
		}
		break;
	case DT_REFR:
	default:
        {
        int mismatch;
        mismatch = pSrcDst[0] ^ 1;

		for(unsigned int I = 1; I < NUM_ELEMS; I++)
		{
            int AcCoefficient;

            if(pSrcDst[I]<0)
                {
                AcCoefficient = CBL_LIBRARY::Limits<Fw16s>::Sat((-pSrcDst[I] * QP * pQPMatrix[I])>>4);
                AcCoefficient = -AcCoefficient;
                }
            else
                AcCoefficient = CBL_LIBRARY::Limits<Fw16s>::Sat((pSrcDst[I] * QP * pQPMatrix[I])>>4);

            mismatch^= AcCoefficient;
            pSrcDst[I] = (Fw16s)AcCoefficient;
         }
        pSrcDst[63]^= mismatch&1;
        break;
        }
     }
	return fwStsNoErr;
}

FwStatus SYS_INLINE quantInv_MPEG2(Fw16s *pSrcDst, int &QP, Fw16s *pQPMatrix)
{
	if(FW_REF::PtrNotOK(pSrcDst, pQPMatrix))return fwStsNullPtrErr;

	switch(Dispatch::Type<DT_SSE2>())
	{
	case DT_SSE3:
	case DT_SSE2:
		{
			const bool bSrcDstIsAligned = FW_REF::IsAligned(pSrcDst,16);
			const bool bQPMatrixIsAligned = FW_REF::IsAligned(pQPMatrix,16);
			__m128i qpConst = _mm_set1_epi16(CBL_LIBRARY::Limits<Fw16s>::Sat(QP));
			__m128i row;
			__m128i qpRow;
            __m128i mask_zero, mask_negative;
			static const __m128i one = _mm_set1_epi16(1);
            static const __m128i zero = _mm_setzero_si128();

			XMM128 mismatch;
			mismatch.i= _mm_set_epi16(0,0,0,0,0,0,0,1);
			for(unsigned int I = 0; I < NUM_COLS; I++)
			{
				row = (bSrcDstIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pSrcDst) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pSrcDst) + I);
				qpRow = (bQPMatrixIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I);

                mask_zero = _mm_cmpeq_epi16(row, zero);
                mask_negative = _mm_cmplt_epi16(row, zero);

                __m128i negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

				row = _mm_adds_epi16(row,row);
				row = _mm_adds_epi16(row,one);

				__m128i low = _mm_mullo_epi16(row, qpRow);
				__m128i high = _mm_mulhi_epi16(row, qpRow);
				row = _mm_unpacklo_epi16(low, high);
				__m128i tmpHigh = _mm_unpackhi_epi16(low, high);
				FW_SSE2::pack32STo16S(row, tmpHigh);

				low = _mm_mullo_epi16(row, qpConst);
				high = _mm_mulhi_epi16(row, qpConst);
				row = _mm_unpacklo_epi16(low, high);
				tmpHigh = _mm_unpackhi_epi16(low, high);
                FW_SSE2::pack32STo16S(row, tmpHigh);

                row = _mm_srli_epi16(row, 5);
                negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                row = _mm_andnot_si128(mask_zero, row);
				mismatch.i = _mm_xor_si128(row,mismatch.i);

				__m128i* p128i = reinterpret_cast<__m128i*>(pSrcDst);
				if(bSrcDstIsAligned)
				{
					_mm_store_si128(&p128i[I], row);
				}
				else
				{
					_mm_storeu_si128(&p128i[I], row);
				}
			}

            mismatch.s16[0] ^= mismatch.s16[1] ^  mismatch.s16[2] ^  mismatch.s16[3] ^ mismatch.s16[4];
			pSrcDst[63] ^= (mismatch.s16[0] ^ mismatch.s16[5] ^  mismatch.s16[6] ^  mismatch.s16[7]) & 1;

		}
		break;
	case DT_REFR:
	default:
        {
        int mismatch = 1;

        for(unsigned int I = 0; I < NUM_ELEMS; I++)
		{
            int coefficient;

            if(pSrcDst[I]==0)
                coefficient = 0;
            else if(pSrcDst[I]<0)
                {
                coefficient = CBL_LIBRARY::Limits<Fw16s>::Sat((( 2*(-pSrcDst[I]) + 1) * QP * pQPMatrix[I])>>5);
                coefficient = -coefficient;
                }
            else
                coefficient = CBL_LIBRARY::Limits<Fw16s>::Sat(((2 * pSrcDst[I] + 1) * QP * pQPMatrix[I])>>5);

            mismatch^= coefficient;
            pSrcDst[I] = (Fw16s)coefficient;
         }
        pSrcDst[63]^= mismatch&1;
        break;
        }
     }
	return fwStsNoErr;

}
} // end namespace OPT_LEVEL
/************************************************************/
FwStatus STDCALL PREFIX_OPT(OPT_PREFIX, fwiQuantInvIntra_MPEG2_16s_C1I)(Fw16s *pSrcDst, int QP, Fw16s *pQPMatrix)
{
	return quantInvIntra_MPEG2(pSrcDst, QP, pQPMatrix);
}

FwStatus STDCALL PREFIX_OPT(OPT_PREFIX, fwiQuantInv_MPEG2_16s_C1I)(Fw16s *pSrcDst, int QP, Fw16s *pQPMatrix)
{
	return quantInv_MPEG2(pSrcDst, QP, pQPMatrix);
}

// Please do NOT remove the above line for CPP files that need to be multipass compiled
// OREFR OSSE2
<commit_msg>Summary: corrected 2 invQuant functions for the BUGS 1943626 and 1943625 <commit_after>/*
Copyright (c) 2006-2008 Advanced Micro Devices, Inc. All Rights Reserved.
This software is subject to the Apache v2.0 License.
*/

/************************************************************/
#include "buildnum.h"
#include "fwVideo.h"
#include "FwSharedCode.h"
#include "FwSharedCode_SSE2.h"

#include <iostream>

using namespace OPT_LEVEL;

extern const unsigned int NUM_COLS;
extern const unsigned int NUM_ELEMS;

namespace OPT_LEVEL
{

FwStatus SYS_INLINE quantInvIntra_MPEG2(Fw16s *pSrcDst, int &QP, Fw16s *pQPMatrix)
{
	if(FW_REF::PtrNotOK(pSrcDst, pQPMatrix))return fwStsNullPtrErr;

	switch(Dispatch::Type<DT_SSE2>())
	{
	case DT_SSE3:
	case DT_SSE2:
		{
			const bool bSrcDstIsAligned = FW_REF::IsAligned(pSrcDst,16);
			const bool bQPMatrixIsAligned = FW_REF::IsAligned(pQPMatrix,16);
			__m128i qpConst = _mm_set_epi16(CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP), CBL_LIBRARY::Limits<Fw16s>::Sat(QP));
			__m128i row;
			__m128i qpRow;
            XMM128 mismatch;
            __m128i mask_negative;
            __m128i zero = _mm_setzero_si128();
            mismatch.i = _mm_setzero_si128();
            Fw16s src1 = pSrcDst[0];

            mismatch.s16[0] = pSrcDst[0] ^ 1;
            pSrcDst[0]= 0;

			for(unsigned int I = 0; I < NUM_COLS; I++)
			{
				row = (bSrcDstIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pSrcDst) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pSrcDst) + I);
				qpRow = (bQPMatrixIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I);

				__m128i low = _mm_mullo_epi16(row, qpRow);
				__m128i high = _mm_mulhi_epi16(row, qpRow);
				row = _mm_unpacklo_epi16(low, high);
				__m128i tmpHigh = _mm_unpackhi_epi16(low, high);
				FW_SSE2::pack32STo16S(row, tmpHigh);

				low = _mm_mullo_epi16(row, qpConst);
				high = _mm_mulhi_epi16(row, qpConst);
				row = _mm_unpacklo_epi16(low, high);
				tmpHigh = _mm_unpackhi_epi16(low, high);
                FW_SSE2::pack32STo16S(row, tmpHigh);

                mask_negative = _mm_cmplt_epi16(row, zero);
                __m128i negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                row = _mm_srli_epi16(row, 4);
                negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                mismatch.i = _mm_xor_si128(row,mismatch.i);

				__m128i* p128i = reinterpret_cast<__m128i*>(pSrcDst);
				if(bSrcDstIsAligned)
				{
					_mm_store_si128(&p128i[I], row);
				}
				else
				{
					_mm_storeu_si128(&p128i[I], row);
				}
			}

			mismatch.s16[0] ^= mismatch.s16[1] ^  mismatch.s16[2] ^  mismatch.s16[3] ^ mismatch.s16[4];
			pSrcDst[63] ^= (mismatch.s16[0] ^ mismatch.s16[5] ^  mismatch.s16[6] ^  mismatch.s16[7]) & 1;
            pSrcDst[0] = src1;
		}
		break;
	case DT_REFR:
	default:
        {
        int mismatch;
        mismatch = pSrcDst[0] ^ 1;

		for(unsigned int I = 1; I < NUM_ELEMS; I++)
		{
            int AcCoefficient;
            float fl_AcCoefficient;

            fl_AcCoefficient = (float)pSrcDst[I] * QP * (float)pQPMatrix[I];
            (fl_AcCoefficient < -CBL_LIBRARY::Limits<S16>::MaxValue()) ? AcCoefficient = -CBL_LIBRARY::Limits<S16>::MaxValue() : (fl_AcCoefficient > CBL_LIBRARY::Limits<S16>::MaxValue()) ? AcCoefficient = CBL_LIBRARY::Limits<S16>::MaxValue() : AcCoefficient = (int)fl_AcCoefficient;

            if(AcCoefficient < 0)
                {
                AcCoefficient = (-AcCoefficient) >> 4;
                AcCoefficient = -AcCoefficient;
                }
            else
                AcCoefficient = AcCoefficient >> 4;

            mismatch^= AcCoefficient;
            pSrcDst[I] = (Fw16s)AcCoefficient;
         }
        pSrcDst[63]^= mismatch&1;
        break;
        }
     }
	return fwStsNoErr;
}

FwStatus SYS_INLINE quantInv_MPEG2(Fw16s *pSrcDst, int &QP, Fw16s *pQPMatrix)
{
	if(FW_REF::PtrNotOK(pSrcDst, pQPMatrix))return fwStsNullPtrErr;

	switch(Dispatch::Type<DT_SSE2>())
	{
	case DT_SSE3:
	case DT_SSE2:
		{
			const bool bSrcDstIsAligned = FW_REF::IsAligned(pSrcDst,16);
			const bool bQPMatrixIsAligned = FW_REF::IsAligned(pQPMatrix,16);
			__m128i qpConst = _mm_set1_epi16(CBL_LIBRARY::Limits<Fw16s>::Sat(QP));
			__m128i row;
			__m128i qpRow;
            __m128i mask_zero, mask_negative;
			static const __m128i one = _mm_set1_epi16(1);
            static const __m128i zero = _mm_setzero_si128();

			XMM128 mismatch;
			mismatch.i= _mm_set_epi16(0,0,0,0,0,0,0,1);
			for(unsigned int I = 0; I < NUM_COLS; I++)
			{
				row = (bSrcDstIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pSrcDst) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pSrcDst) + I);
				qpRow = (bQPMatrixIsAligned)? _mm_load_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I) : _mm_loadu_si128(reinterpret_cast<__m128i*>(pQPMatrix) + I);

                mask_zero = _mm_cmpeq_epi16(row, zero);

				row = _mm_adds_epi16(row,row);
				row = _mm_adds_epi16(row,one);

				__m128i low = _mm_mullo_epi16(row, qpRow);
				__m128i high = _mm_mulhi_epi16(row, qpRow);
				row = _mm_unpacklo_epi16(low, high);
				__m128i tmpHigh = _mm_unpackhi_epi16(low, high);
				FW_SSE2::pack32STo16S(row, tmpHigh);

				low = _mm_mullo_epi16(row, qpConst);
				high = _mm_mulhi_epi16(row, qpConst);
				row = _mm_unpacklo_epi16(low, high);
				tmpHigh = _mm_unpackhi_epi16(low, high);
                FW_SSE2::pack32STo16S(row, tmpHigh);

                mask_negative = _mm_cmplt_epi16(row, zero);
                __m128i negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                row = _mm_srli_epi16(row, 5);
                negative_nums = _mm_and_si128(mask_negative, row);
                negative_nums = _mm_subs_epi16(zero, negative_nums);
                row = _mm_andnot_si128(mask_negative, row);
                row = _mm_or_si128(row, negative_nums);

                row = _mm_andnot_si128(mask_zero, row);
				mismatch.i = _mm_xor_si128(row,mismatch.i);

				__m128i* p128i = reinterpret_cast<__m128i*>(pSrcDst);
				if(bSrcDstIsAligned)
				{
					_mm_store_si128(&p128i[I], row);
				}
				else
				{
					_mm_storeu_si128(&p128i[I], row);
				}
			}

            mismatch.s16[0] ^= mismatch.s16[1] ^  mismatch.s16[2] ^  mismatch.s16[3] ^ mismatch.s16[4];
			pSrcDst[63] ^= (mismatch.s16[0] ^ mismatch.s16[5] ^  mismatch.s16[6] ^  mismatch.s16[7]) & 1;

		}
		break;
	case DT_REFR:
	default:
        {
        int mismatch = 1;

        for(unsigned int I = 0; I < NUM_ELEMS; I++)
		{
            int coefficient;
            float fl_coefficient;

            if(pSrcDst[I]==0)
                coefficient = 0;
            else
                {
                fl_coefficient = (2 * (float)pSrcDst[I] + 1) * QP * (float)pQPMatrix[I];
                (fl_coefficient < -CBL_LIBRARY::Limits<S16>::MaxValue()) ? coefficient = -CBL_LIBRARY::Limits<S16>::MaxValue() : (fl_coefficient > CBL_LIBRARY::Limits<S16>::MaxValue()) ? coefficient = CBL_LIBRARY::Limits<S16>::MaxValue() : coefficient = (int)fl_coefficient;
                if(coefficient < 0)
                    {
                    coefficient = (-coefficient)>>5;
                    coefficient = -coefficient;
                    }
                else
                    coefficient = coefficient >> 5;
                }

            mismatch^= coefficient;
            pSrcDst[I] = (Fw16s)coefficient;
         }
        pSrcDst[63]^= mismatch&1;
        break;
        }
     }
	return fwStsNoErr;

}
} // end namespace OPT_LEVEL
/************************************************************/
FwStatus STDCALL PREFIX_OPT(OPT_PREFIX, fwiQuantInvIntra_MPEG2_16s_C1I)(Fw16s *pSrcDst, int QP, Fw16s *pQPMatrix)
{
	return quantInvIntra_MPEG2(pSrcDst, QP, pQPMatrix);
}

FwStatus STDCALL PREFIX_OPT(OPT_PREFIX, fwiQuantInv_MPEG2_16s_C1I)(Fw16s *pSrcDst, int QP, Fw16s *pQPMatrix)
{
	return quantInv_MPEG2(pSrcDst, QP, pQPMatrix);
}

// Please do NOT remove the above line for CPP files that need to be multipass compiled
// OREFR OSSE2
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  nkuiWrapper.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#define NK_IMPLEMENTATION
#include "nkuiWrapper.h"
#include "Core/Memory/Memory.h"
#include "Input/Input.h"
#include "NKUIShaders.h"
#include "glm/mat4x4.hpp"
#include "glm/gtc/matrix_transform.hpp"

namespace Oryol {
namespace _priv {

//------------------------------------------------------------------------------
void
nkuiWrapper::Setup(const NKUISetup& setup) {
    o_assert_dbg(!this->isValid);
    this->isValid = true;

    // create resources
    this->gfxResLabel = Gfx::PushResourceLabel();
    this->createDefaultFont(setup);
    this->createMeshAndPipeline();
    Gfx::PopResourceLabel();

    // initialize nuklear
    nk_init_default(&this->ctx, &this->defaultFont->handle);
    nk_buffer_init_default(&this->cmds);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::Discard() {
    o_assert_dbg(this->isValid);
    this->defaultFont = nullptr;
    nk_buffer_free(&this->cmds);
    nk_font_atlas_clear(&this->atlas);
    nk_free(&this->ctx);
    Gfx::DestroyResources(this->gfxResLabel);
    this->isValid = false;
}

//------------------------------------------------------------------------------
void
nkuiWrapper::createDefaultFont(const NKUISetup& setup) {
    o_assert_dbg(nullptr == this->defaultFont);

    // let Nuklear create a font bitmap
    nk_font_atlas_init_default(&this->atlas);
    nk_font_atlas_begin(&this->atlas);
    this->defaultFont = nk_font_atlas_add_default(&this->atlas, 13, 0);
    int imgWidth, imgHeight;
    const void* imgData = nk_font_atlas_bake(&this->atlas, &imgWidth, &imgHeight, NK_FONT_ATLAS_RGBA32);

    // create Oryol Gfx texture from font image data
    auto texSetup = TextureSetup::FromPixelData(imgWidth, imgHeight, 1, TextureType::Texture2D, PixelFormat::RGBA8);
    texSetup.Sampler.WrapU = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.WrapV = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.MinFilter = TextureFilterMode::Nearest;
    texSetup.Sampler.MagFilter = TextureFilterMode::Nearest;
    const int imgSize = imgWidth*imgHeight * PixelFormat::ByteSize(PixelFormat::RGBA8);
    texSetup.ImageData.Sizes[0][0] = imgSize;
    int texId = this->curTexId++;
    this->textures[texId] = Gfx::CreateResource(texSetup, imgData, imgSize);
    nk_font_atlas_end(&this->atlas, nk_handle_id(texId), &this->nullTex);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::createMeshAndPipeline() {

    // create mesh with dynamic vertex- and index-buffer
    auto mshSetup = MeshSetup::Empty(MaxNumVertices, Usage::Stream, IndexType::Index16, MaxNumIndices, Usage::Stream);
    mshSetup.Layout
        .Add(VertexAttr::Position, VertexFormat::Float2)
        .Add(VertexAttr::TexCoord0, VertexFormat::Float2)
        .Add(VertexAttr::Color0, VertexFormat::UByte4N);
    o_assert_dbg(mshSetup.Layout.ByteSize() == sizeof(struct nk_draw_vertex));
    this->drawState.Mesh[0] = Gfx::CreateResource(mshSetup);

    // create pipeline state object
    Id shd = Gfx::CreateResource(NKUIShader::Setup());
    auto ps = PipelineSetup::FromLayoutAndShader(mshSetup.Layout, shd);
    ps.DepthStencilState.DepthWriteEnabled = false;
    ps.DepthStencilState.DepthCmpFunc = CompareFunc::Always;
    ps.BlendState.BlendEnabled = true;
    ps.BlendState.SrcFactorRGB = BlendFactor::SrcAlpha;
    ps.BlendState.DstFactorRGB = BlendFactor::OneMinusSrcAlpha;
    ps.BlendState.ColorFormat = Gfx::DisplayAttrs().ColorPixelFormat;
    ps.BlendState.DepthFormat = Gfx::DisplayAttrs().DepthPixelFormat;
    ps.BlendState.ColorWriteMask = PixelChannel::RGB;
    ps.RasterizerState.ScissorTestEnabled = true;
    ps.RasterizerState.CullFaceEnabled = false;
    ps.RasterizerState.SampleCount = Gfx::DisplayAttrs().SampleCount;
    this->drawState.Pipeline = Gfx::CreateResource(ps);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::NewFrame() {
    nk_input_begin(&this->ctx);
    if (Input::KeyboardAttached()) {
        nk_input_key(&this->ctx, NK_KEY_DEL, Input::KeyDown(Key::Delete));
        nk_input_key(&this->ctx, NK_KEY_ENTER, Input::KeyDown(Key::Enter));
        nk_input_key(&this->ctx, NK_KEY_TAB, Input::KeyDown(Key::Tab));
        nk_input_key(&this->ctx, NK_KEY_BACKSPACE, Input::KeyDown(Key::BackSpace));
        nk_input_key(&this->ctx, NK_KEY_LEFT, Input::KeyDown(Key::Left));
        nk_input_key(&this->ctx, NK_KEY_RIGHT, Input::KeyDown(Key::Right));
        nk_input_key(&this->ctx, NK_KEY_UP, Input::KeyDown(Key::Up));
        nk_input_key(&this->ctx, NK_KEY_DOWN, Input::KeyDown(Key::Down));
        if (Input::KeyPressed(Key::LeftControl) || Input::KeyPressed(Key::RightControl)) {
            nk_input_key(&this->ctx, NK_KEY_COPY, Input::KeyDown(Key::C));
            nk_input_key(&this->ctx, NK_KEY_PASTE, Input::KeyDown(Key::V));
            nk_input_key(&this->ctx, NK_KEY_CUT, Input::KeyDown(Key::X));
        }
        else {
            nk_input_key(&this->ctx, NK_KEY_COPY, 0);
            nk_input_key(&this->ctx, NK_KEY_PASTE, 0);
            nk_input_key(&this->ctx, NK_KEY_CUT, 0);
        }
    }
    if (Input::MouseAttached()) {
        const glm::vec2& mousePos = Input::MousePosition();
        int x = int(mousePos.x);
        int y = int(mousePos.y);
        bool lmb = Input::MouseButtonPressed(MouseButton::Left)|Input::MouseButtonDown(MouseButton::Left);
        bool mmb = Input::MouseButtonPressed(MouseButton::Middle)|Input::MouseButtonDown(MouseButton::Middle);
        bool rmb = Input::MouseButtonPressed(MouseButton::Right)|Input::MouseButtonDown(MouseButton::Right);
        nk_input_motion(&this->ctx, x, y);
        nk_input_button(&this->ctx, NK_BUTTON_LEFT, x, y, lmb);
        nk_input_button(&this->ctx, NK_BUTTON_MIDDLE, x, y, mmb);
        nk_input_button(&this->ctx, NK_BUTTON_RIGHT, x, y, rmb);
    }
    nk_input_end(&this->ctx);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::Draw() {

    // upload vertex and index data
    nk_convert_config config = { };
    config.global_alpha = 1.0f;
    config.shape_AA = NK_ANTI_ALIASING_ON;
    config.line_AA = NK_ANTI_ALIASING_ON;
    config.circle_segment_count = 22;
    config.curve_segment_count = 22;
    config.arc_segment_count = 22;
    config.null = this->nullTex;
    struct nk_buffer vbuf, ibuf;
    nk_buffer_init_fixed(&vbuf, this->vertexData, sizeof(this->vertexData));
    nk_buffer_init_fixed(&ibuf, this->indexData, sizeof(this->indexData));
    nk_convert(&this->ctx, &this->cmds, &vbuf, &ibuf, &config);
    if (vbuf.needed > 0) {
        Gfx::UpdateVertices(this->drawState.Mesh[0], this->vertexData, vbuf.needed);
    }
    if (ibuf.needed > 0) {
        Gfx::UpdateIndices(this->drawState.Mesh[0], this->indexData, ibuf.needed);
    }

    // compute projection matrix
    const DisplayAttrs& attrs = Gfx::DisplayAttrs();
    const float width = float(attrs.FramebufferWidth);
    const float height = float(attrs.FramebufferHeight);
    NKUIShader::VSParams vsParams;
    vsParams.Proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);

    // render draw commands
    Id curTexture;
    const struct nk_draw_command* cmd = nullptr;
    int elm_offset = 0;
    nk_draw_foreach(cmd, &this->ctx, &this->cmds) {
        const Id& newTexture = this->textures[(int)cmd->texture.id];
        if (curTexture != newTexture) {
            this->drawState.FSTexture[NKUITextures::Texture] = newTexture;
            curTexture = newTexture;
            Gfx::ApplyDrawState(this->drawState);
            Gfx::ApplyUniformBlock(vsParams);
        }
        Gfx::ApplyScissorRect((int)cmd->clip_rect.x,
                              (int)(height - (cmd->clip_rect.y + cmd->clip_rect.h)),
                              (int)(cmd->clip_rect.w),
                              (int)(cmd->clip_rect.h));
        Gfx::Draw(PrimitiveGroup(elm_offset, cmd->elem_count));
        elm_offset += cmd->elem_count;
    }
    nk_clear(&this->ctx);
}

} // namespace _priv
} // namespace Oryol
<commit_msg>Warning fixes<commit_after>//------------------------------------------------------------------------------
//  nkuiWrapper.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#define NK_IMPLEMENTATION
#include "nkuiWrapper.h"
#include "Core/Memory/Memory.h"
#include "Input/Input.h"
#include "NKUIShaders.h"
#include "glm/mat4x4.hpp"
#include "glm/gtc/matrix_transform.hpp"

namespace Oryol {
namespace _priv {

//------------------------------------------------------------------------------
void
nkuiWrapper::Setup(const NKUISetup& setup) {
    o_assert_dbg(!this->isValid);
    this->isValid = true;

    // create resources
    this->gfxResLabel = Gfx::PushResourceLabel();
    this->createDefaultFont(setup);
    this->createMeshAndPipeline();
    Gfx::PopResourceLabel();

    // initialize nuklear
    nk_init_default(&this->ctx, &this->defaultFont->handle);
    nk_buffer_init_default(&this->cmds);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::Discard() {
    o_assert_dbg(this->isValid);
    this->defaultFont = nullptr;
    nk_buffer_free(&this->cmds);
    nk_font_atlas_clear(&this->atlas);
    nk_free(&this->ctx);
    Gfx::DestroyResources(this->gfxResLabel);
    this->isValid = false;
}

//------------------------------------------------------------------------------
void
nkuiWrapper::createDefaultFont(const NKUISetup& setup) {
    o_assert_dbg(nullptr == this->defaultFont);

    // let Nuklear create a font bitmap
    nk_font_atlas_init_default(&this->atlas);
    nk_font_atlas_begin(&this->atlas);
    this->defaultFont = nk_font_atlas_add_default(&this->atlas, 13, 0);
    int imgWidth, imgHeight;
    const void* imgData = nk_font_atlas_bake(&this->atlas, &imgWidth, &imgHeight, NK_FONT_ATLAS_RGBA32);

    // create Oryol Gfx texture from font image data
    auto texSetup = TextureSetup::FromPixelData(imgWidth, imgHeight, 1, TextureType::Texture2D, PixelFormat::RGBA8);
    texSetup.Sampler.WrapU = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.WrapV = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.MinFilter = TextureFilterMode::Nearest;
    texSetup.Sampler.MagFilter = TextureFilterMode::Nearest;
    const int imgSize = imgWidth*imgHeight * PixelFormat::ByteSize(PixelFormat::RGBA8);
    texSetup.ImageData.Sizes[0][0] = imgSize;
    int texId = this->curTexId++;
    this->textures[texId] = Gfx::CreateResource(texSetup, imgData, imgSize);
    nk_font_atlas_end(&this->atlas, nk_handle_id(texId), &this->nullTex);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::createMeshAndPipeline() {

    // create mesh with dynamic vertex- and index-buffer
    auto mshSetup = MeshSetup::Empty(MaxNumVertices, Usage::Stream, IndexType::Index16, MaxNumIndices, Usage::Stream);
    mshSetup.Layout
        .Add(VertexAttr::Position, VertexFormat::Float2)
        .Add(VertexAttr::TexCoord0, VertexFormat::Float2)
        .Add(VertexAttr::Color0, VertexFormat::UByte4N);
    o_assert_dbg(mshSetup.Layout.ByteSize() == sizeof(struct nk_draw_vertex));
    this->drawState.Mesh[0] = Gfx::CreateResource(mshSetup);

    // create pipeline state object
    Id shd = Gfx::CreateResource(NKUIShader::Setup());
    auto ps = PipelineSetup::FromLayoutAndShader(mshSetup.Layout, shd);
    ps.DepthStencilState.DepthWriteEnabled = false;
    ps.DepthStencilState.DepthCmpFunc = CompareFunc::Always;
    ps.BlendState.BlendEnabled = true;
    ps.BlendState.SrcFactorRGB = BlendFactor::SrcAlpha;
    ps.BlendState.DstFactorRGB = BlendFactor::OneMinusSrcAlpha;
    ps.BlendState.ColorFormat = Gfx::DisplayAttrs().ColorPixelFormat;
    ps.BlendState.DepthFormat = Gfx::DisplayAttrs().DepthPixelFormat;
    ps.BlendState.ColorWriteMask = PixelChannel::RGB;
    ps.RasterizerState.ScissorTestEnabled = true;
    ps.RasterizerState.CullFaceEnabled = false;
    ps.RasterizerState.SampleCount = Gfx::DisplayAttrs().SampleCount;
    this->drawState.Pipeline = Gfx::CreateResource(ps);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::NewFrame() {
    nk_input_begin(&this->ctx);
    if (Input::KeyboardAttached()) {
        nk_input_key(&this->ctx, NK_KEY_DEL, Input::KeyDown(Key::Delete));
        nk_input_key(&this->ctx, NK_KEY_ENTER, Input::KeyDown(Key::Enter));
        nk_input_key(&this->ctx, NK_KEY_TAB, Input::KeyDown(Key::Tab));
        nk_input_key(&this->ctx, NK_KEY_BACKSPACE, Input::KeyDown(Key::BackSpace));
        nk_input_key(&this->ctx, NK_KEY_LEFT, Input::KeyDown(Key::Left));
        nk_input_key(&this->ctx, NK_KEY_RIGHT, Input::KeyDown(Key::Right));
        nk_input_key(&this->ctx, NK_KEY_UP, Input::KeyDown(Key::Up));
        nk_input_key(&this->ctx, NK_KEY_DOWN, Input::KeyDown(Key::Down));
        if (Input::KeyPressed(Key::LeftControl) || Input::KeyPressed(Key::RightControl)) {
            nk_input_key(&this->ctx, NK_KEY_COPY, Input::KeyDown(Key::C));
            nk_input_key(&this->ctx, NK_KEY_PASTE, Input::KeyDown(Key::V));
            nk_input_key(&this->ctx, NK_KEY_CUT, Input::KeyDown(Key::X));
        }
        else {
            nk_input_key(&this->ctx, NK_KEY_COPY, 0);
            nk_input_key(&this->ctx, NK_KEY_PASTE, 0);
            nk_input_key(&this->ctx, NK_KEY_CUT, 0);
        }
    }
    if (Input::MouseAttached()) {
        const glm::vec2& mousePos = Input::MousePosition();
        int x = int(mousePos.x);
        int y = int(mousePos.y);
        bool lmb = Input::MouseButtonPressed(MouseButton::Left)|Input::MouseButtonDown(MouseButton::Left);
        bool mmb = Input::MouseButtonPressed(MouseButton::Middle)|Input::MouseButtonDown(MouseButton::Middle);
        bool rmb = Input::MouseButtonPressed(MouseButton::Right)|Input::MouseButtonDown(MouseButton::Right);
        nk_input_motion(&this->ctx, x, y);
        nk_input_button(&this->ctx, NK_BUTTON_LEFT, x, y, lmb);
        nk_input_button(&this->ctx, NK_BUTTON_MIDDLE, x, y, mmb);
        nk_input_button(&this->ctx, NK_BUTTON_RIGHT, x, y, rmb);
    }
    nk_input_end(&this->ctx);
}

//------------------------------------------------------------------------------
void
nkuiWrapper::Draw() {

    // upload vertex and index data
    nk_convert_config config;
    Memory::Clear(&config, sizeof(config));
    config.global_alpha = 1.0f;
    config.shape_AA = NK_ANTI_ALIASING_ON;
    config.line_AA = NK_ANTI_ALIASING_ON;
    config.circle_segment_count = 22;
    config.curve_segment_count = 22;
    config.arc_segment_count = 22;
    config.null = this->nullTex;
    struct nk_buffer vbuf, ibuf;
    nk_buffer_init_fixed(&vbuf, this->vertexData, sizeof(this->vertexData));
    nk_buffer_init_fixed(&ibuf, this->indexData, sizeof(this->indexData));
    nk_convert(&this->ctx, &this->cmds, &vbuf, &ibuf, &config);
    if (vbuf.needed > 0) {
        Gfx::UpdateVertices(this->drawState.Mesh[0], this->vertexData, int(vbuf.needed));
    }
    if (ibuf.needed > 0) {
        Gfx::UpdateIndices(this->drawState.Mesh[0], this->indexData, int(ibuf.needed));
    }

    // compute projection matrix
    const DisplayAttrs& attrs = Gfx::DisplayAttrs();
    const float width = float(attrs.FramebufferWidth);
    const float height = float(attrs.FramebufferHeight);
    NKUIShader::VSParams vsParams;
    vsParams.Proj = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f);

    // render draw commands
    Id curTexture;
    const struct nk_draw_command* cmd = nullptr;
    int elm_offset = 0;
    nk_draw_foreach(cmd, &this->ctx, &this->cmds) {
        const Id& newTexture = this->textures[(int)cmd->texture.id];
        if (curTexture != newTexture) {
            this->drawState.FSTexture[NKUITextures::Texture] = newTexture;
            curTexture = newTexture;
            Gfx::ApplyDrawState(this->drawState);
            Gfx::ApplyUniformBlock(vsParams);
        }
        Gfx::ApplyScissorRect((int)cmd->clip_rect.x,
                              (int)(height - (cmd->clip_rect.y + cmd->clip_rect.h)),
                              (int)(cmd->clip_rect.w),
                              (int)(cmd->clip_rect.h));
        Gfx::Draw(PrimitiveGroup(elm_offset, cmd->elem_count));
        elm_offset += cmd->elem_count;
    }
    nk_clear(&this->ctx);
}

} // namespace _priv
} // namespace Oryol
<|endoftext|>


<commit_before>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef WIN32
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <netdb.h>
#endif
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <ctime>
#include "packetsender.h"

const int Tins::PacketSender::INVALID_RAW_SOCKET = -1;
const uint32_t Tins::PacketSender::DEFAULT_TIMEOUT = 2;

Tins::PacketSender::PacketSender(uint32_t recv_timeout, uint32_t usec) :
    _sockets(SOCKETS_END, INVALID_RAW_SOCKET), _timeout(recv_timeout), _timeout_usec(usec) {
    _types[IP_SOCKET] = IPPROTO_RAW;
    _types[ICMP_SOCKET] = IPPROTO_ICMP;
}

Tins::PacketSender::~PacketSender() {
    for(unsigned i(0); i < _sockets.size(); ++i) {
        if(_sockets[i] != INVALID_RAW_SOCKET)
            ::close(_sockets[i]);
    }
}

bool Tins::PacketSender::open_l2_socket() {
    if (_sockets[ETHER_SOCKET] != INVALID_RAW_SOCKET)
        return true;
    int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sock == -1)
        return false;
    _sockets[ETHER_SOCKET] = sock;
    return true;
}

bool Tins::PacketSender::open_l3_socket(SocketType type) {
    int socktype = find_type(type);
    if(socktype == -1)
        return false;
    if(_sockets[type] != INVALID_RAW_SOCKET)
        return true;
    int sockfd;
    sockfd = socket(AF_INET, SOCK_RAW, socktype);
    if (sockfd < 0)
        return false;

    const int on = 1;
    setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,(const void *)&on,sizeof(on));

    _sockets[type] = sockfd;
    return true;
}

bool Tins::PacketSender::close_socket(uint32_t flag) {
    if(flag >= SOCKETS_END || _sockets[flag] == INVALID_RAW_SOCKET)
        return false;
    close(_sockets[flag]);
    _sockets[flag] = INVALID_RAW_SOCKET;
    return true;
}

bool Tins::PacketSender::send(PDU *pdu) {
    return pdu->send(this);
}

Tins::PDU *Tins::PacketSender::send_recv(PDU *pdu) {
    if(!pdu->send(this))
        return 0;
    return pdu->recv_response(this);
}

bool Tins::PacketSender::send_l2(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr) {

    if(!open_l2_socket())
        return false;

    uint32_t sz;
    int sock = _sockets[ETHER_SOCKET];
    uint8_t *buffer = pdu->serialize(sz);
    bool ret_val = (sendto(sock, buffer, sz, 0, link_addr, len_addr) != -1);
    delete[] buffer;

    return ret_val;
}

Tins::PDU *Tins::PacketSender::recv_l2(PDU *pdu, struct sockaddr *link_addr, uint32_t len_addr) {
    if(!open_l2_socket())
        return 0;
    return recv_match_loop(_sockets[ETHER_SOCKET], pdu, link_addr, len_addr);
}

Tins::PDU *Tins::PacketSender::recv_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
    if(!open_l3_socket(type))
        return 0;
    return recv_match_loop(_sockets[type], pdu, link_addr, len_addr);
}

bool Tins::PacketSender::send_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
    bool ret_val = true;
    if(!open_l3_socket(type))
        ret_val = false;
    if (ret_val) {
        uint32_t sz;
        int sock = _sockets[type];
        uint8_t *buffer = pdu->serialize(sz);
        ret_val = (sendto(sock, buffer, sz, 0, link_addr, len_addr) != -1);
        delete[] buffer;
    }
    return ret_val;
}

Tins::PDU *Tins::PacketSender::recv_match_loop(int sock, PDU *pdu, struct sockaddr* link_addr, socklen_t addrlen) {
    fd_set readfds;
    struct timeval timeout;
    int read;
    uint8_t buffer[2048];
    time_t end_time = time(0) + _timeout;
    timeout.tv_sec  = _timeout;
    timeout.tv_usec = _timeout_usec;
    while(true) {
        FD_ZERO(&readfds);
        FD_SET(sock, &readfds);
        if((read = select(sock + 1, &readfds, 0, 0, &timeout)) == -1)
            return 0;
        if(FD_ISSET(sock, &readfds)) {
            ssize_t size = recvfrom(sock, buffer, 2048, 0, link_addr, &addrlen);
            if(pdu->matches_response(buffer, size))
                return pdu->clone_packet(buffer, size);
        }
        time_t this_time = time(0);
        if(end_time <= this_time)
            return 0;
        timeout.tv_sec = end_time - this_time;
    }
    return 0;
}

int Tins::PacketSender::find_type(SocketType type) {
    SocketTypeMap::iterator it = _types.find(type);
    if(it == _types.end())
        return -1;
    else
        return it->second;
}
<commit_msg>Fixed bug when using microsecond presition on PacketSender::recv_match_loop.<commit_after>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef WIN32
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <sys/time.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <netdb.h>
#endif
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <ctime>
#include "packetsender.h"

const int Tins::PacketSender::INVALID_RAW_SOCKET = -1;
const uint32_t Tins::PacketSender::DEFAULT_TIMEOUT = 2;

Tins::PacketSender::PacketSender(uint32_t recv_timeout, uint32_t usec) :
    _sockets(SOCKETS_END, INVALID_RAW_SOCKET), _timeout(recv_timeout), _timeout_usec(usec) {
    _types[IP_SOCKET] = IPPROTO_RAW;
    _types[ICMP_SOCKET] = IPPROTO_ICMP;
}

Tins::PacketSender::~PacketSender() {
    for(unsigned i(0); i < _sockets.size(); ++i) {
        if(_sockets[i] != INVALID_RAW_SOCKET)
            ::close(_sockets[i]);
    }
}

bool Tins::PacketSender::open_l2_socket() {
    if (_sockets[ETHER_SOCKET] != INVALID_RAW_SOCKET)
        return true;
    int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sock == -1)
        return false;
    _sockets[ETHER_SOCKET] = sock;
    return true;
}

bool Tins::PacketSender::open_l3_socket(SocketType type) {
    int socktype = find_type(type);
    if(socktype == -1)
        return false;
    if(_sockets[type] != INVALID_RAW_SOCKET)
        return true;
    int sockfd;
    sockfd = socket(AF_INET, SOCK_RAW, socktype);
    if (sockfd < 0)
        return false;

    const int on = 1;
    setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,(const void *)&on,sizeof(on));

    _sockets[type] = sockfd;
    return true;
}

bool Tins::PacketSender::close_socket(uint32_t flag) {
    if(flag >= SOCKETS_END || _sockets[flag] == INVALID_RAW_SOCKET)
        return false;
    close(_sockets[flag]);
    _sockets[flag] = INVALID_RAW_SOCKET;
    return true;
}

bool Tins::PacketSender::send(PDU *pdu) {
    return pdu->send(this);
}

Tins::PDU *Tins::PacketSender::send_recv(PDU *pdu) {
    if(!pdu->send(this))
        return 0;
    return pdu->recv_response(this);
}

bool Tins::PacketSender::send_l2(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr) {

    if(!open_l2_socket())
        return false;

    uint32_t sz;
    int sock = _sockets[ETHER_SOCKET];
    uint8_t *buffer = pdu->serialize(sz);
    bool ret_val = (sendto(sock, buffer, sz, 0, link_addr, len_addr) != -1);
    delete[] buffer;

    return ret_val;
}

Tins::PDU *Tins::PacketSender::recv_l2(PDU *pdu, struct sockaddr *link_addr, uint32_t len_addr) {
    if(!open_l2_socket())
        return 0;
    return recv_match_loop(_sockets[ETHER_SOCKET], pdu, link_addr, len_addr);
}

Tins::PDU *Tins::PacketSender::recv_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
    if(!open_l3_socket(type))
        return 0;
    return recv_match_loop(_sockets[type], pdu, link_addr, len_addr);
}

bool Tins::PacketSender::send_l3(PDU *pdu, struct sockaddr* link_addr, uint32_t len_addr, SocketType type) {
    bool ret_val = true;
    if(!open_l3_socket(type))
        ret_val = false;
    if (ret_val) {
        uint32_t sz;
        int sock = _sockets[type];
        uint8_t *buffer = pdu->serialize(sz);
        ret_val = (sendto(sock, buffer, sz, 0, link_addr, len_addr) != -1);
        delete[] buffer;
    }
    return ret_val;
}

Tins::PDU *Tins::PacketSender::recv_match_loop(int sock, PDU *pdu, struct sockaddr* link_addr, socklen_t addrlen) {
    fd_set readfds;
    struct timeval timeout,  end_time;
    int read;
    uint8_t buffer[2048];
    timeout.tv_sec  = _timeout;
    end_time.tv_sec = time(0) + _timeout;
    end_time.tv_usec = timeout.tv_usec = _timeout_usec;
    while(true) {
        FD_ZERO(&readfds);
        FD_SET(sock, &readfds);
        if((read = select(sock + 1, &readfds, 0, 0, &timeout)) == -1)
            return 0;
        if(FD_ISSET(sock, &readfds)) {
            ssize_t size = recvfrom(sock, buffer, 2048, 0, link_addr, &addrlen);
            if(pdu->matches_response(buffer, size))
                return pdu->clone_packet(buffer, size);
        }
        struct timeval this_time;
        gettimeofday(&this_time, 0);
        if(end_time.tv_sec <= this_time.tv_sec && end_time.tv_usec <= this_time.tv_usec)
            return 0;
        timeout.tv_sec = end_time.tv_sec - this_time.tv_sec;
        timeout.tv_usec = end_time.tv_usec;
    }
    return 0;
}

int Tins::PacketSender::find_type(SocketType type) {
    SocketTypeMap::iterator it = _types.find(type);
    if(it == _types.end())
        return -1;
    else
        return it->second;
}
<|endoftext|>


<commit_before>//
//  nifti_hdr.cpp
//  NiftiImage
//
//  Created by Tobias Wood on 08/07/2013.
//  Copyright (c) 2013 Tobias Wood. All rights reserved.
//

#include <memory>
#include <vector>
#include <iostream>
#include <getopt.h>

#include "Nifti.h"

using namespace std;

const string usage = "nifti_hdr - A utility for getting information from Nifti headers.\n\
\n\
Usage: nifti_hdr [options] file1 [other files]\n\
By default the abbreviated header will be printed for each file.\n\
Abbreviated, full and compare modes are mutually exclusive.\n\
\n\
Options:\n\
	-d, --dims :  Print the size of each dimension for each file.\n\
	-v, --vox :   Print the voxel sizes for each file (with units). \n\
	-t, --trans : Print the XForm to physical space with precedence.\n\
	-a, --abbrev: Print the abbreviated header.\n\
	-f, --full:   Print the entire header.\n\
	-c, --comp:   Compare first file to all others and print message if the.\n\
	              physical spaces are different.\n\
	-h, --help:   Print this message and quit.\n\
";

enum Modes {
	Nothing = 0,
	Abbreviated,
	Full,
	Compare
};

static int mode = Nothing;
static int printDims = false, printVoxdims = false, printSize = false, printData = false,
           printTransform = false, printExtensions = false;

static struct option long_options[] =
{
	{"dims",   no_argument, &printDims, true},
	{"vox",    no_argument, &printVoxdims, true},
	{"form",   no_argument, &printTransform, true},
	{"size",   no_argument, &printSize, true},
	{"data",   no_argument, &printData, true},
	{"abbrev", no_argument, &mode, Abbreviated},
	{"full",   no_argument, &mode, Full},
	{"comp",   no_argument, &mode, Compare},
	{"help",   no_argument, 0, 'h'},
	{"ext",    no_argument, 0, 'e'},
	{0, 0, 0, 0}
};

string voxMessage(const Nifti &im) {
	stringstream m;
	m << "Voxel sizes: " << im.voxDims().transpose() << " " << im.spaceUnits();
	if (im.voxDims().rows() > 3) {
		m << "/" << im.timeUnits();
	}
	return m.str();
}

string sizeMessage(const Nifti &im) {
	stringstream m;
	m << "Voxels per slice, per volume, total: "
      << im.voxelsPerSlice() << ", " << im.voxelsPerVolume() << ", " << im.voxelsTotal();
	return m.str();
}

string dataMessage(const Nifti &im) {
	stringstream m;
	m << "Datatype: " << Nifti::TypeInfo(im.datatype()).name << ", size in bytes: " << Nifti::TypeInfo(im.datatype()).size;
	return m.str();
}

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "dvtafchse", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'd': printDims = true; break;
			case 'v': printVoxdims = true; break;
			case 't': printTransform = true; break;
			case 's': printSize = true; break;
			case 'e': printExtensions = true; break;
			case 'a': mode = Abbreviated; break;
			case 'f': mode = Full; break;
			case 'c': mode = Compare; break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		exit(EXIT_FAILURE);
	}
	if (optind == 1) { // No options specified, default is short header
		mode = Abbreviated;
	}
	vector<Nifti> images;
	images.reserve(argc - optind); // emplace_back can still trigger copies if the vector has to be resized
	for (;optind < argc; optind++) {
		images.emplace_back(argv[optind], Nifti::Mode::ReadHeader);
	}

	if (mode == Compare) { // Compare first image to all others and check headers are compatible
		for (auto im = images.begin() + 1; im != images.end(); im++) {
			if (!images[0].matchesSpace(*im)) {
				cout << "Header does not match against file: " << im->imagePath() << endl;
			}
		}
	}

	for (auto& im: images) {
		if (printDims) cout << im.dims().transpose() << endl;
		if (printVoxdims) cout << voxMessage(im) << endl;
		if (printTransform) cout << im.transform().matrix() << endl;
		if (printSize) cout << sizeMessage(im) << endl;
		if (printData) cout << dataMessage(im) << endl;

		if (mode == Abbreviated) {
			cout << "Short Nifti Header for file: " << im.imagePath() << endl;
			cout << "Dimensions:  " << im.dims().transpose() << endl;
			cout << voxMessage(im) << endl;
			cout << "XForm matrix: " << endl << im.transform().matrix() << endl;
			cout << "Number of extensions: " << im.extensions().size() << endl;
		} else if (mode == Full) {
			cout << "Full Nifti Header for file: " << im.imagePath() << endl;
			cout << dataMessage(im) << endl;
			cout << "Dimensions: " << im.dims().transpose() << endl;
			cout << voxMessage(im) << endl;

			cout << "Calibration (min, max): " << im.calibration_min << ", " << im.calibration_max << endl;
			cout << "Scaling (slope, inter): " << im.scaling_slope << ", " << im.scaling_inter << endl;
			cout << "Dimension labels (Phase, Freq, Slice):   " << im.phase_dim << ", " << im.freq_dim << ", " << im.slice_dim << endl;
			cout << "Slice info (Code, Start, End, Duration): " << ", " << im.slice_code << ", " << im.slice_start << ", " << im.slice_end << ", " << im.slice_duration << endl;
			cout << "Slice name: " << im.sliceName() << endl;
			cout << "Time offset: " << im.toffset << endl;

			cout << "Intent name:   " << im.intent_name << endl;
			cout << "Intent code:   " << im.intentName() << endl;
			cout << "Intent params: " << im.intent_p1 << ", " << im.intent_p2 << ", " << im.intent_p3 << endl;
			cout << "Description: " << im.description << endl;
			cout << "Aux File:    " << im.aux_file << endl;
			cout << "QForm: " << Nifti::XFormName(im.qcode()) << endl;
			cout << im.qform().matrix() << endl;
			cout << "SForm: " << Nifti::XFormName(im.scode()) << endl;
			cout << im.sform().matrix() << endl;
			cout << "Extensions: " << endl;
			for (auto &e : im.extensions()) {
				cout << "Extension Code: " << e.code() << endl;
				string out(e.data().begin(), e.data().end());
				cout << out << endl;
			}
		}
	}

	return EXIT_SUCCESS;
}

<commit_msg>Temporary changes to nifti_hdr to test changes to read/write interface.<commit_after>//
//  nifti_hdr.cpp
//  NiftiImage
//
//  Created by Tobias Wood on 08/07/2013.
//  Copyright (c) 2013 Tobias Wood. All rights reserved.
//

#include <memory>
#include <vector>
#include <iostream>
#include <getopt.h>

#include "Nifti.h"

using namespace std;

const string usage = "nifti_hdr - A utility for getting information from Nifti headers.\n\
\n\
Usage: nifti_hdr [options] file1 [other files]\n\
By default the abbreviated header will be printed for each file.\n\
Abbreviated, full and compare modes are mutually exclusive.\n\
\n\
Options:\n\
	-d, --dims :  Print the size of each dimension for each file.\n\
	-v, --vox :   Print the voxel sizes for each file (with units). \n\
	-t, --trans : Print the XForm to physical space with precedence.\n\
	-a, --abbrev: Print the abbreviated header.\n\
	-f, --full:   Print the entire header.\n\
	-c, --comp:   Compare first file to all others and print message if the.\n\
	              physical spaces are different.\n\
	-h, --help:   Print this message and quit.\n\
";

enum Modes {
	Nothing = 0,
	Abbreviated,
	Full,
	Compare
};

static int mode = Nothing;
static int printDims = false, printVoxdims = false, printSize = false, printData = false,
           printTransform = false, printExtensions = false;

static struct option long_options[] =
{
	{"dims",   no_argument, &printDims, true},
	{"vox",    no_argument, &printVoxdims, true},
	{"form",   no_argument, &printTransform, true},
	{"size",   no_argument, &printSize, true},
	{"data",   no_argument, &printData, true},
	{"abbrev", no_argument, &mode, Abbreviated},
	{"full",   no_argument, &mode, Full},
	{"comp",   no_argument, &mode, Compare},
	{"help",   no_argument, 0, 'h'},
	{"ext",    no_argument, 0, 'e'},
	{0, 0, 0, 0}
};

string voxMessage(const Nifti &im) {
	stringstream m;
	m << "Voxel sizes: " << im.voxDims().transpose() << " " << im.spaceUnits();
	if (im.voxDims().rows() > 3) {
		m << "/" << im.timeUnits();
	}
	return m.str();
}

string sizeMessage(const Nifti &im) {
	stringstream m;
	m << "Voxels per slice, per volume, total: "
      << im.voxelsPerSlice() << ", " << im.voxelsPerVolume() << ", " << im.voxelsTotal();
	return m.str();
}

string dataMessage(const Nifti &im) {
	stringstream m;
	m << "Datatype: " << Nifti::TypeInfo(im.datatype()).name << ", size in bytes: " << Nifti::TypeInfo(im.datatype()).size;
	return m.str();
}

int main(int argc, char **argv) {
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, "dvtafchse", long_options, &indexptr)) != -1) {
		switch (c) {
			case 'd': printDims = true; break;
			case 'v': printVoxdims = true; break;
			case 't': printTransform = true; break;
			case 's': printSize = true; break;
			case 'e': printExtensions = true; break;
			case 'a': mode = Abbreviated; break;
			case 'f': mode = Full; break;
			case 'c': mode = Compare; break;
			case '?': // getopt will print an error message
			case 'h':
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		exit(EXIT_FAILURE);
	}
	if (optind == 1) { // No options specified, default is short header
		mode = Abbreviated;
	}
	vector<Nifti> images;
	images.reserve(argc - optind); // emplace_back can still trigger copies if the vector has to be resized
	for (;optind < argc; optind++) {
		images.emplace_back(argv[optind], Nifti::Mode::Read);
	}

	if (mode == Compare) { // Compare first image to all others and check headers are compatible
		for (auto im = images.begin() + 1; im != images.end(); im++) {
			if (!images[0].matchesSpace(*im)) {
				cout << "Header does not match against file: " << im->imagePath() << endl;
			}
		}
	}

	for (auto& im: images) {
		if (printDims) cout << im.dims().transpose() << endl;
		if (printVoxdims) cout << voxMessage(im) << endl;
		if (printTransform) cout << im.transform().matrix() << endl;
		if (printSize) cout << sizeMessage(im) << endl;
		if (printData) cout << dataMessage(im) << endl;

		if (mode == Abbreviated) {
			cout << "Short Nifti Header for file: " << im.imagePath() << endl;
			cout << "Dimensions:  " << im.dims().transpose() << endl;
			cout << voxMessage(im) << endl;
			cout << "XForm matrix: " << endl << im.transform().matrix() << endl;
			cout << "Number of extensions: " << im.extensions().size() << endl;
		} else if (mode == Full) {
			cout << "Full Nifti Header for file: " << im.imagePath() << endl;
			cout << dataMessage(im) << endl;
			cout << "Dimensions: " << im.dims().transpose() << endl;
			cout << voxMessage(im) << endl;

			cout << "Calibration (min, max): " << im.calibration_min << ", " << im.calibration_max << endl;
			cout << "Scaling (slope, inter): " << im.scaling_slope << ", " << im.scaling_inter << endl;
			cout << "Dimension labels (Phase, Freq, Slice):   " << im.phase_dim << ", " << im.freq_dim << ", " << im.slice_dim << endl;
			cout << "Slice info (Code, Start, End, Duration): " << ", " << im.slice_code << ", " << im.slice_start << ", " << im.slice_end << ", " << im.slice_duration << endl;
			cout << "Slice name: " << im.sliceName() << endl;
			cout << "Time offset: " << im.toffset << endl;

			cout << "Intent name:   " << im.intent_name << endl;
			cout << "Intent code:   " << im.intentName() << endl;
			cout << "Intent params: " << im.intent_p1 << ", " << im.intent_p2 << ", " << im.intent_p3 << endl;
			cout << "Description: " << im.description << endl;
			cout << "Aux File:    " << im.aux_file << endl;
			cout << "QForm: " << Nifti::XFormName(im.qcode()) << endl;
			cout << im.qform().matrix() << endl;
			cout << "SForm: " << Nifti::XFormName(im.scode()) << endl;
			cout << im.sform().matrix() << endl;
			cout << "Extensions: " << endl;
			for (auto &e : im.extensions()) {
				cout << "Extension Code: " << e.code() << endl;
				string out(e.data().begin(), e.data().end());
				cout << out << endl;
			}
		}
		vector<float> data(8);
		Nifti::ArrayXs start(3); Nifti::ArrayXs size(3);
		start << 4, 2, 10;
		size << 4, 2, 1;
		cout << "Before size: " << data.size() << endl;
		im.readWriteVoxels(start, size, data);
		cout << "After size: " << data.size() << endl;
		for (size_t i = 0; i < 8; i++) cout << data.at(i) << "\t";
	}

	return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#include "ParallelContext.hpp"

#include "Options.hpp"

using namespace std;

// This is just a default size; the buffer will be resized later according to #part and #threads
#define PARALLEL_BUF_SIZE (128 * 1024)

size_t ParallelContext::_num_threads = 1;
size_t ParallelContext::_num_ranks = 1;
size_t ParallelContext::_rank_id = 0;
thread_local size_t ParallelContext::_thread_id = 0;
std::vector<ThreadType> ParallelContext::_threads;
std::vector<char> ParallelContext::_parallel_buf;
std::unordered_map<ThreadIDType, ParallelContext> ParallelContext::_thread_ctx_map;
MutexType ParallelContext::mtx;

#ifdef _RAXML_MPI
MPI_Comm ParallelContext::_comm = MPI_COMM_WORLD;
bool ParallelContext::_owns_comm = true;
#endif

void ParallelContext::init_mpi(int argc, char * argv[], void * comm)
{
#ifdef _RAXML_MPI
  {
    int tmp;

    if (comm)
    {
      // TODO we should think how to get rid of this ugly cast!
      _comm = *((MPI_Comm*) comm);
      _owns_comm = false;
    }
    else
    {
      _comm = MPI_COMM_WORLD;
      _owns_comm = true;
      MPI_Init(&argc, &argv);
    }

    MPI_Comm_rank(_comm, &tmp);
    _rank_id = (size_t) tmp;
    MPI_Comm_size(_comm, &tmp);
    _num_ranks = (size_t) tmp;
//    printf("size: %lu, rank: %lu\n", _num_ranks, _rank_id);
  }
#else
  RAXML_UNUSED(argc);
  RAXML_UNUSED(argv);
  RAXML_UNUSED(comm);
#endif
}

void ParallelContext::start_thread(size_t thread_id, const std::function<void()>& thread_main)
{
  ParallelContext::_thread_id = thread_id;
  thread_main();
}

void ParallelContext::init_pthreads(const Options& opts, const std::function<void()>& thread_main)
{
  _num_threads = opts.num_threads;
  _parallel_buf.reserve(PARALLEL_BUF_SIZE);

#ifdef _RAXML_PTHREADS
  /* Launch threads */
  for (size_t i = 1; i < _num_threads; ++i)
  {
    _threads.emplace_back(ParallelContext::start_thread, i, thread_main);
  }
#endif
}

void ParallelContext::resize_buffer(size_t size)
{
  _parallel_buf.reserve(size);
}

void ParallelContext::finalize(bool force)
{
#ifdef _RAXML_PTHREADS
  for (thread& t: _threads)
  {
    if (force)
      t.detach();
    else
      t.join();
  }
  _threads.clear();
#endif

#ifdef _RAXML_MPI
  if (_owns_comm)
  {
    if (force)
      MPI_Abort(_comm, -1);
    else
      MPI_Barrier(_comm);

    MPI_Finalize();
  }
  else
    MPI_Barrier(_comm);
#endif
}

void ParallelContext::barrier()
{
#ifdef _RAXML_MPI
  mpi_barrier();
#endif

#ifdef _RAXML_PTHREADS
  thread_barrier();
#endif
}

void ParallelContext::mpi_barrier()
{
#ifdef _RAXML_MPI
  if (_thread_id == 0 && _num_ranks > 1)
    MPI_Barrier(_comm);
#endif
}

void ParallelContext::thread_barrier()
{
  static volatile unsigned int barrier_counter = 0;
  static thread_local volatile int myCycle = 0;
  static volatile int proceed = 0;

  __sync_fetch_and_add( &barrier_counter, 1);

  if(_thread_id == 0)
  {
    while(barrier_counter != ParallelContext::_num_threads);
    barrier_counter = 0;
    proceed = !proceed;
  }
  else
  {
    while(myCycle == proceed);
    myCycle = !myCycle;
  }
}

void ParallelContext::thread_reduce(double * data, size_t size, int op)
{
  /* synchronize */
  thread_barrier();

  double *double_buf = (double*) _parallel_buf.data();

  /* collect data from threads */
  size_t i, j;
  for (i = 0; i < size; ++i)
    double_buf[_thread_id * size + i] = data[i];

  /* synchronize */
  thread_barrier();

  /* reduce */
  for (i = 0; i < size; ++i)
  {
    switch(op)
    {
      case PLLMOD_COMMON_REDUCE_SUM:
      {
        data[i] = 0.;
        for (j = 0; j < ParallelContext::_num_threads; ++j)
          data[i] += double_buf[j * size + i];
      }
      break;
      case PLLMOD_COMMON_REDUCE_MAX:
      {
        data[i] = _parallel_buf[i];
        for (j = 1; j < ParallelContext::_num_threads; ++j)
          data[i] = max(data[i], double_buf[j * size + i]);
      }
      break;
      case PLLMOD_COMMON_REDUCE_MIN:
      {
        data[i] = _parallel_buf[i];
        for (j = 1; j < ParallelContext::_num_threads; ++j)
          data[i] = min(data[i], double_buf[j * size + i]);
      }
      break;
    }
  }

  //needed?
//  parallel_barrier(useropt);
}

void ParallelContext::parallel_reduce(double * data, size_t size, int op)
{
#ifdef _RAXML_PTHREADS
  if (_num_threads > 1)
    thread_reduce(data, size, op);
#endif

#ifdef _RAXML_MPI
  if (_num_ranks > 1)
  {
    thread_barrier();

    if (_thread_id == 0)
    {
      MPI_Op reduce_op;
      if (op == PLLMOD_COMMON_REDUCE_SUM)
        reduce_op = MPI_SUM;
      else if (op == PLLMOD_COMMON_REDUCE_MAX)
        reduce_op = MPI_MAX;
      else if (op == PLLMOD_COMMON_REDUCE_MIN)
        reduce_op = MPI_MIN;
      else
        assert(0);

#if 1
      MPI_Allreduce(MPI_IN_PLACE, data, size, MPI_DOUBLE, reduce_op, _comm);
#else
      // not sure if MPI_IN_PLACE will work in all cases...
      MPI_Allreduce(data, _parallel_buf.data(), size, MPI_DOUBLE, reduce_op, _comm);
      memcpy(data, _parallel_buf.data(), size * sizeof(double));
#endif
    }

    if (_num_threads > 1)
      thread_broadcast(0, data, size * sizeof(double));
  }
#endif
}

void ParallelContext::parallel_reduce_cb(void * context, double * data, size_t size, int op)
{
  ParallelContext::parallel_reduce(data, size, op);
  RAXML_UNUSED(context);
}

void ParallelContext::thread_broadcast(size_t source_id, void * data, size_t size)
{
  /* write to buf */
  if (_thread_id == source_id)
  {
    memcpy((void *) _parallel_buf.data(), data, size);
  }

  /* synchronize */
  thread_barrier();

//  pthread_barrier_wait(&barrier);
  __sync_synchronize();

  /* read from buf*/
  if (_thread_id != source_id)
  {
    memcpy(data, (void *) _parallel_buf.data(), size);
  }

  thread_barrier();
}

void ParallelContext::thread_send_master(size_t source_id, void * data, size_t size) const
{
  /* write to buf */
  if (_thread_id == source_id && data && size)
  {
    memcpy((void *) _parallel_buf.data(), data, size);
  }

  /* synchronize */
  barrier();

//  pthread_barrier_wait(&barrier);
  __sync_synchronize();

  /* read from buf*/
  if (_thread_id == 0)
  {
    memcpy(data, (void *) _parallel_buf.data(), size);
  }

  barrier();
}

void ParallelContext::mpi_gather_custom(std::function<int(void*,int)> prepare_send_cb,
                                        std::function<void(void*,int)> process_recv_cb)
{
#ifdef _RAXML_MPI
  /* we're gonna use _parallel_buf, so make sure other threads don't interfere... */
  UniqueLock lock;

  if (_rank_id == 0)
  {
    for (size_t r = 1; r < _num_ranks; ++r)
    {
      int recv_size;
      MPI_Status status;
      MPI_Probe(r, 0, _comm, &status);
      MPI_Get_count(&status, MPI_BYTE, &recv_size);

//      printf("recv: %lu\n", recv_size);

      _parallel_buf.reserve(recv_size);

      MPI_Recv((void*) _parallel_buf.data(), recv_size, MPI_BYTE,
               r, 0, _comm, MPI_STATUS_IGNORE);

      process_recv_cb(_parallel_buf.data(), recv_size);
    }
  }
  else
  {
    auto send_size = prepare_send_cb(_parallel_buf.data(), _parallel_buf.capacity());
//    printf("sent: %lu\n", send_size);

    MPI_Send(_parallel_buf.data(), send_size, MPI_BYTE, 0, 0, _comm);
  }
#else
  RAXML_UNUSED(prepare_send_cb);
  RAXML_UNUSED(process_recv_cb);
#endif
}

<commit_msg>fix pthread min/max reduction<commit_after>#include "ParallelContext.hpp"

#include "Options.hpp"

using namespace std;

// This is just a default size; the buffer will be resized later according to #part and #threads
#define PARALLEL_BUF_SIZE (128 * 1024)

size_t ParallelContext::_num_threads = 1;
size_t ParallelContext::_num_ranks = 1;
size_t ParallelContext::_rank_id = 0;
thread_local size_t ParallelContext::_thread_id = 0;
std::vector<ThreadType> ParallelContext::_threads;
std::vector<char> ParallelContext::_parallel_buf;
std::unordered_map<ThreadIDType, ParallelContext> ParallelContext::_thread_ctx_map;
MutexType ParallelContext::mtx;

#ifdef _RAXML_MPI
MPI_Comm ParallelContext::_comm = MPI_COMM_WORLD;
bool ParallelContext::_owns_comm = true;
#endif

void ParallelContext::init_mpi(int argc, char * argv[], void * comm)
{
#ifdef _RAXML_MPI
  {
    int tmp;

    if (comm)
    {
      // TODO we should think how to get rid of this ugly cast!
      _comm = *((MPI_Comm*) comm);
      _owns_comm = false;
    }
    else
    {
      _comm = MPI_COMM_WORLD;
      _owns_comm = true;
      MPI_Init(&argc, &argv);
    }

    MPI_Comm_rank(_comm, &tmp);
    _rank_id = (size_t) tmp;
    MPI_Comm_size(_comm, &tmp);
    _num_ranks = (size_t) tmp;
//    printf("size: %lu, rank: %lu\n", _num_ranks, _rank_id);
  }
#else
  RAXML_UNUSED(argc);
  RAXML_UNUSED(argv);
  RAXML_UNUSED(comm);
#endif
}

void ParallelContext::start_thread(size_t thread_id, const std::function<void()>& thread_main)
{
  ParallelContext::_thread_id = thread_id;
  thread_main();
}

void ParallelContext::init_pthreads(const Options& opts, const std::function<void()>& thread_main)
{
  _num_threads = opts.num_threads;
  _parallel_buf.reserve(PARALLEL_BUF_SIZE);

#ifdef _RAXML_PTHREADS
  /* Launch threads */
  for (size_t i = 1; i < _num_threads; ++i)
  {
    _threads.emplace_back(ParallelContext::start_thread, i, thread_main);
  }
#endif
}

void ParallelContext::resize_buffer(size_t size)
{
  _parallel_buf.reserve(size);
}

void ParallelContext::finalize(bool force)
{
#ifdef _RAXML_PTHREADS
  for (thread& t: _threads)
  {
    if (force)
      t.detach();
    else
      t.join();
  }
  _threads.clear();
#endif

#ifdef _RAXML_MPI
  if (_owns_comm)
  {
    if (force)
      MPI_Abort(_comm, -1);
    else
      MPI_Barrier(_comm);

    MPI_Finalize();
  }
  else
    MPI_Barrier(_comm);
#endif
}

void ParallelContext::barrier()
{
#ifdef _RAXML_MPI
  mpi_barrier();
#endif

#ifdef _RAXML_PTHREADS
  thread_barrier();
#endif
}

void ParallelContext::mpi_barrier()
{
#ifdef _RAXML_MPI
  if (_thread_id == 0 && _num_ranks > 1)
    MPI_Barrier(_comm);
#endif
}

void ParallelContext::thread_barrier()
{
  static volatile unsigned int barrier_counter = 0;
  static thread_local volatile int myCycle = 0;
  static volatile int proceed = 0;

  __sync_fetch_and_add( &barrier_counter, 1);

  if(_thread_id == 0)
  {
    while(barrier_counter != ParallelContext::_num_threads);
    barrier_counter = 0;
    proceed = !proceed;
  }
  else
  {
    while(myCycle == proceed);
    myCycle = !myCycle;
  }
}

void ParallelContext::thread_reduce(double * data, size_t size, int op)
{
  /* synchronize */
  thread_barrier();

  double *double_buf = (double*) _parallel_buf.data();

  /* collect data from threads */
  size_t i, j;
  for (i = 0; i < size; ++i)
    double_buf[_thread_id * size + i] = data[i];

  /* synchronize */
  thread_barrier();

  /* reduce */
  for (i = 0; i < size; ++i)
  {
    switch(op)
    {
      case PLLMOD_COMMON_REDUCE_SUM:
      {
        data[i] = 0.;
        for (j = 0; j < ParallelContext::_num_threads; ++j)
          data[i] += double_buf[j * size + i];
      }
      break;
      case PLLMOD_COMMON_REDUCE_MAX:
      {
        data[i] = double_buf[i];
        for (j = 1; j < ParallelContext::_num_threads; ++j)
          data[i] = max(data[i], double_buf[j * size + i]);
      }
      break;
      case PLLMOD_COMMON_REDUCE_MIN:
      {
        data[i] = double_buf[i];
        for (j = 1; j < ParallelContext::_num_threads; ++j)
          data[i] = min(data[i], double_buf[j * size + i]);
      }
      break;
    }
  }

  //needed?
//  parallel_barrier(useropt);
}

void ParallelContext::parallel_reduce(double * data, size_t size, int op)
{
#ifdef _RAXML_PTHREADS
  if (_num_threads > 1)
    thread_reduce(data, size, op);
#endif

#ifdef _RAXML_MPI
  if (_num_ranks > 1)
  {
    thread_barrier();

    if (_thread_id == 0)
    {
      MPI_Op reduce_op;
      if (op == PLLMOD_COMMON_REDUCE_SUM)
        reduce_op = MPI_SUM;
      else if (op == PLLMOD_COMMON_REDUCE_MAX)
        reduce_op = MPI_MAX;
      else if (op == PLLMOD_COMMON_REDUCE_MIN)
        reduce_op = MPI_MIN;
      else
        assert(0);

#if 1
      MPI_Allreduce(MPI_IN_PLACE, data, size, MPI_DOUBLE, reduce_op, _comm);
#else
      // not sure if MPI_IN_PLACE will work in all cases...
      MPI_Allreduce(data, _parallel_buf.data(), size, MPI_DOUBLE, reduce_op, _comm);
      memcpy(data, _parallel_buf.data(), size * sizeof(double));
#endif
    }

    if (_num_threads > 1)
      thread_broadcast(0, data, size * sizeof(double));
  }
#endif
}

void ParallelContext::parallel_reduce_cb(void * context, double * data, size_t size, int op)
{
  ParallelContext::parallel_reduce(data, size, op);
  RAXML_UNUSED(context);
}

void ParallelContext::thread_broadcast(size_t source_id, void * data, size_t size)
{
  /* write to buf */
  if (_thread_id == source_id)
  {
    memcpy((void *) _parallel_buf.data(), data, size);
  }

  /* synchronize */
  thread_barrier();

//  pthread_barrier_wait(&barrier);
  __sync_synchronize();

  /* read from buf*/
  if (_thread_id != source_id)
  {
    memcpy(data, (void *) _parallel_buf.data(), size);
  }

  thread_barrier();
}

void ParallelContext::thread_send_master(size_t source_id, void * data, size_t size) const
{
  /* write to buf */
  if (_thread_id == source_id && data && size)
  {
    memcpy((void *) _parallel_buf.data(), data, size);
  }

  /* synchronize */
  barrier();

//  pthread_barrier_wait(&barrier);
  __sync_synchronize();

  /* read from buf*/
  if (_thread_id == 0)
  {
    memcpy(data, (void *) _parallel_buf.data(), size);
  }

  barrier();
}

void ParallelContext::mpi_gather_custom(std::function<int(void*,int)> prepare_send_cb,
                                        std::function<void(void*,int)> process_recv_cb)
{
#ifdef _RAXML_MPI
  /* we're gonna use _parallel_buf, so make sure other threads don't interfere... */
  UniqueLock lock;

  if (_rank_id == 0)
  {
    for (size_t r = 1; r < _num_ranks; ++r)
    {
      int recv_size;
      MPI_Status status;
      MPI_Probe(r, 0, _comm, &status);
      MPI_Get_count(&status, MPI_BYTE, &recv_size);

//      printf("recv: %lu\n", recv_size);

      _parallel_buf.reserve(recv_size);

      MPI_Recv((void*) _parallel_buf.data(), recv_size, MPI_BYTE,
               r, 0, _comm, MPI_STATUS_IGNORE);

      process_recv_cb(_parallel_buf.data(), recv_size);
    }
  }
  else
  {
    auto send_size = prepare_send_cb(_parallel_buf.data(), _parallel_buf.capacity());
//    printf("sent: %lu\n", send_size);

    MPI_Send(_parallel_buf.data(), send_size, MPI_BYTE, 0, 0, _comm);
  }
#else
  RAXML_UNUSED(prepare_send_cb);
  RAXML_UNUSED(process_recv_cb);
#endif
}

<|endoftext|>


<commit_before>//
//  PlaylistChooser.cpp
//  Kepler
//
//  Created by Tom Carden on 7/10/11.
//  Copyright 2011 Bloom Studio, Inc. All rights reserved.
//

#include <string>
#include "cinder/Vector.h"
#include "cinder/PolyLine.h"
#include "cinder/ImageIo.h"
#include "cinder/Rand.h"
#include "cinder/Path2d.h"
#include "PlaylistChooser.h"
#include "NodeArtist.h"
#include "BloomScene.h"
#include "Globals.h"

using namespace ci;
using namespace ci::app;
using namespace std;

void PlaylistChooser::setup( const Font &font, const Vec2f &interfaceSize )
{
    mFont					= font;
    mFontHeight             = mFont.getAscent() + mFont.getDescent();

    mTouchDragId			= 0;
    mTouchDragStartPos		= Vec2i( 0, 0 );
    mTouchDragStartOffset	= 0.0f;
    mTouchDragPlaylistIndex	= -1;

	mTouchVel				= 0.0f;
	mTouchPos				= Vec2i( 0, 0 );
	mTouchPrevPos			= Vec2i( 0, 0 );

    mOffsetX				= 0.0f;

	mNumPlaylists			= 0;
	mIsDragging				= false;

	mPlaylistSize			= Vec2f( 150.f, 30.0f );
	mSpacerWidth			= 15.0f;
	mStartY					= 11.0f;

	mPrevIndex				= -1;
	mCurrentIndex			= 0;

    mInterfaceSize          = interfaceSize;

    mFullRect.set( 0, 0, mInterfaceSize.x, mStartY + mFontHeight + mStartY );
}

bool PlaylistChooser::touchBegan( ci::app::TouchEvent::Touch touch )
{
    if( mData == NULL || mTouchDragPlaylistIndex >= 0 ) return false;

    mIsDragging		= false;
	mTouchPrevPos	= mTouchPos;
	mTouchPos		= globalToLocal( touch.getPos() );
	mTouchVel		= 0.0f;

    Vec2f padding	= Vec2f( 10.0f, 10.0f );

    // see if we're touching a specific button
    mTouchDragPlaylistIndex = -1;
	for( int i = 0; i < mPlaylistRects.size(); i++ ){
		if( mPlaylistRects[i] && mPlaylistRects[i]->inflated( padding ).contains( mTouchPos ) ){
			mTouchDragPlaylistIndex = i;
            break;
        }
	}

    // allow dragging (but not selection) inside the whole panel as well
    if( mTouchDragPlaylistIndex >= 0 || mFullRect.contains(mTouchPos) ) {
        mTouchDragId			= touch.getId();
        mTouchDragStartPos		= mTouchPos;
        mTouchDragStartOffset	= mOffsetX;
        return true;
    }

    return false;
}

bool PlaylistChooser::touchMoved( ci::app::TouchEvent::Touch touch )
{
    if (mData == NULL) return false;

    mIsDragging = true;

    mTouchPrevPos	= mTouchPos;
    mTouchPos		= globalToLocal( touch.getPos() );
    mOffsetX		= mTouchDragStartOffset + (mTouchPos.x - mTouchDragStartPos.x);
    mTouchVel		= mTouchPos.x - mTouchPrevPos.x;

    return true;
}

bool PlaylistChooser::touchEnded( ci::app::TouchEvent::Touch touch )
{
    if (mData == NULL) return false;

	mIsDragging		= false;

    mTouchPos		= globalToLocal( touch.getPos() );
    mOffsetX		= mTouchDragStartOffset + (mTouchPos.x - mTouchDragStartPos.x);

    if (mTouchDragPlaylistIndex >= 0) {

        float movement	= mTouchDragStartPos.distance( mTouchPos );
        if (movement < 15.0f) {
            // TODO: also measure time and don't allow long selection gaps
            mCurrentIndex = mTouchDragPlaylistIndex;
            mPrevIndex = mCurrentIndex; // set this so that we won't fire the callback twice
            mCbPlaylistSelected.call( mData->mPlaylists[mTouchDragPlaylistIndex] );
            mCbPlaylistTouched.call( mData->mPlaylists[mTouchDragPlaylistIndex] );
        }
    }

    mTouchDragId			= 0;
    mTouchDragPlaylistIndex = -1;
    mTouchDragStartPos		= mTouchPos;
    mTouchDragStartOffset	= mOffsetX;

    return true;
}

void PlaylistChooser::update()
{
    if (mData == NULL) return;

    mInterfaceSize  = getRoot()->getInterfaceSize();

    // update full rect for layout, hit testing etc.
    mFullRect.set( 0, 0, mInterfaceSize.x, mStartY + mFontHeight + mStartY );

    // total size of all playlist labels + spaces
    float totalWidth = (mPlaylistSize.x * mNumPlaylists) + (mSpacerWidth * (mNumPlaylists+1));
    totalWidth = max( totalWidth, mInterfaceSize.x );

    // min/max drag positions to leave things in the center
//    float maxOffsetX = (mInterfaceSize.x / 2.0f) - (mPlaylistSize.x / 2.0f);              // when dragging right
//    float minOffsetX = (mPlaylistSize.x / 2.0f) + (mInterfaceSize.x / 2.0f) - totalWidth; // when dragging left
    // min/max drag positions to keep things on screen
    float maxOffsetX = 0.0f;  // when dragging right
    float minOffsetX = mPlaylistSize.x - totalWidth; // when dragging left

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

	if( !mIsDragging ){
        // carry on with inertia/momentum scrolling
		mOffsetX += mTouchVel;

        // spring back if we've gone too far
		if( mOffsetX < minOffsetX ){
			mTouchVel = 0.0f;
			mOffsetX += ( minOffsetX - mOffsetX ) * 0.2f;
		}
        else if( mOffsetX > maxOffsetX ){
			mTouchVel = 0.0f;
			mOffsetX += ( maxOffsetX - mOffsetX ) * 0.2f;
		}

        if( abs( mTouchVel ) > 1.0f ) {
            // slow down if we're moving fast:
            mTouchVel *= 0.95f;
        }
        else {
            // otherwise we're slow enough to think again
            // so cancel momentum completely:
			mTouchVel		 = 0.0f;
		}
	}

    ////////// update placement rects

    mPlaylistRects.clear();

    const float y  = mStartY;
    const float h  = mFontHeight;

    float xPos = mOffsetX + mSpacerWidth;

    for( int i = 0; i < mNumPlaylists; i++ )
	{
        if( xPos < mInterfaceSize.x && xPos + mPlaylistSize.x > 0.0f )
		{
			if (!mTextures[i]) {
				makeTexture( i, mData->mPlaylists[i] );
            }
            // put texture rect at center of playlist rect
			const float cx = xPos + mPlaylistSize.x * 0.5f;
			const float w2 = mTextures[i].getWidth() * 0.5f;
			mPlaylistRects.push_back( RectRef( new Rectf( cx - w2, y, cx + w2, y + h ) ) );
        }
        else {
			mPlaylistRects.push_back( RectRef() );
		}

        xPos += mSpacerWidth + mPlaylistSize.x;
    }
}

void PlaylistChooser::draw()
{
	if( mData == NULL ) return;

	gl::disableDepthRead();
	gl::disableDepthWrite();
	gl::enableAlphaBlending();
	gl::enableAdditiveBlending();

    float r = BRIGHT_BLUE.r;
    float g = BRIGHT_BLUE.g;
    float b = BRIGHT_BLUE.b;
    // opacity is supplied by UiLayer::draw

    gl::color( ColorA( r, g, b, mOpacity * 0.125f ) );
    gl::drawLine( Vec2f(0,0), Vec2f(mInterfaceSize.x,0) );

//    float xPos = mOffsetX + mSpacerWidth;

    for( int i = 0; i < mNumPlaylists; i++ )
	{
        RectRef rect = mPlaylistRects[i];
        if( rect && rect->x1 < mInterfaceSize.x && rect->x2 > 0.0f )
        {
            if ( i == mCurrentIndex ) {
                gl::color( ColorA( BRIGHT_BLUE, mOpacity ) );
            }
            else if ( i == mTouchDragPlaylistIndex ) {
                gl::color( ColorA( 1, 1, 1, mOpacity ) );
            }
            else {
                gl::color( ColorA( BLUE, mOpacity ) );
            }

            gl::draw( mTextures[i], rect->getUpperLeft() );

//            gl::color( Color::white() );
//            gl::drawStrokedRect( *rect );
        }

//        gl::color( Color::white() );
//        gl::drawStrokedRect( Rectf( xPos, mStartY, xPos + mPlaylistSize.x, mStartY + mFontHeight ) );
//
//        xPos += mPlaylistSize.x + mSpacerWidth;
    }

//    Rectf center( (mInterfaceSize.x - mPlaylistSize.x) / 2.0f, 0.0f,
//                  (mInterfaceSize.x + mPlaylistSize.x) / 2.0f, mFullRect.getHeight() );
//
//    gl::color( ColorA( BRIGHT_BLUE, alpha * 0.15f ) );
//    gl::drawSolidRect( center );
//
//    gl::color( ColorA( BRIGHT_BLUE, alpha * 0.5f ) );
//    gl::drawSolidRect( Rectf( center.x1, center.y1 + 0.0f, center.x2, center.y1 + 3.0f ) );
//    gl::drawSolidRect( Rectf( center.x1, center.y2 - 3.0f, center.x2, center.y2 - 0.0f ) );

	gl::disableDepthRead();
	gl::disableDepthWrite();
	gl::enableAlphaBlending();
}

void PlaylistChooser::makeTexture( int index, ipod::PlaylistRef playlist )
{
    // FIXME: measure the texture and shorten the name if needed
	string name = playlist->getPlaylistName();
	if( name.length() > 19 ){
		name = name.substr( 0, 18 );
		name += "...";
	}
	TextLayout layout;
	layout.setFont( mFont );
	layout.setColor( Color::white() );
	layout.addLine( name );
	mTextures[index] = gl::Texture( layout.render( true, false ) );
}

float PlaylistChooser::getAlpha( float x )
{
	float per		= x / mInterfaceSize.x;
	float invCos	= ( 1.0f - (float)cos( per * TWO_PI ) ) * 0.5f;
	float cosPer	= pow( invCos, 0.5f );
	return cosPer;
}

void PlaylistChooser::setDataWorldCam( Data *data, World *world, CameraPersp *cam )
{
    mData			= data;
    mWorld			= world;
    mCam			= cam;
	mNumPlaylists	= mData->mPlaylists.size();
    mTextures.resize(mNumPlaylists);
}

float PlaylistChooser::getHeight()
{
    return mFullRect.getHeight();
}

<commit_msg>fix drag limits for small numbers of playlists<commit_after>//
//  PlaylistChooser.cpp
//  Kepler
//
//  Created by Tom Carden on 7/10/11.
//  Copyright 2011 Bloom Studio, Inc. All rights reserved.
//

#include <string>
#include "cinder/Vector.h"
#include "cinder/PolyLine.h"
#include "cinder/ImageIo.h"
#include "cinder/Rand.h"
#include "cinder/Path2d.h"
#include "PlaylistChooser.h"
#include "NodeArtist.h"
#include "BloomScene.h"
#include "Globals.h"

using namespace ci;
using namespace ci::app;
using namespace std;

void PlaylistChooser::setup( const Font &font, const Vec2f &interfaceSize )
{
    mFont					= font;
    mFontHeight             = mFont.getAscent() + mFont.getDescent();

    mTouchDragId			= 0;
    mTouchDragStartPos		= Vec2i( 0, 0 );
    mTouchDragStartOffset	= 0.0f;
    mTouchDragPlaylistIndex	= -1;

	mTouchVel				= 0.0f;
	mTouchPos				= Vec2i( 0, 0 );
	mTouchPrevPos			= Vec2i( 0, 0 );

    mOffsetX				= 0.0f;

	mNumPlaylists			= 0;
	mIsDragging				= false;

	mPlaylistSize			= Vec2f( 150.f, 30.0f );
	mSpacerWidth			= 15.0f;
	mStartY					= 11.0f;

	mPrevIndex				= -1;
	mCurrentIndex			= 0;

    mInterfaceSize          = interfaceSize;

    mFullRect.set( 0, 0, mInterfaceSize.x, mStartY + mFontHeight + mStartY );
}

bool PlaylistChooser::touchBegan( ci::app::TouchEvent::Touch touch )
{
    if( mData == NULL || mTouchDragPlaylistIndex >= 0 ) return false;

    mIsDragging		= false;
	mTouchPrevPos	= mTouchPos;
	mTouchPos		= globalToLocal( touch.getPos() );
	mTouchVel		= 0.0f;

    Vec2f padding	= Vec2f( 10.0f, 10.0f );

    // see if we're touching a specific button
    mTouchDragPlaylistIndex = -1;
	for( int i = 0; i < mPlaylistRects.size(); i++ ){
		if( mPlaylistRects[i] && mPlaylistRects[i]->inflated( padding ).contains( mTouchPos ) ){
			mTouchDragPlaylistIndex = i;
            break;
        }
	}

    // allow dragging (but not selection) inside the whole panel as well
    if( mTouchDragPlaylistIndex >= 0 || mFullRect.contains(mTouchPos) ) {
        mTouchDragId			= touch.getId();
        mTouchDragStartPos		= mTouchPos;
        mTouchDragStartOffset	= mOffsetX;
        return true;
    }

    return false;
}

bool PlaylistChooser::touchMoved( ci::app::TouchEvent::Touch touch )
{
    if (mData == NULL) return false;

    mIsDragging = true;

    mTouchPrevPos	= mTouchPos;
    mTouchPos		= globalToLocal( touch.getPos() );
    mOffsetX		= mTouchDragStartOffset + (mTouchPos.x - mTouchDragStartPos.x);
    mTouchVel		= mTouchPos.x - mTouchPrevPos.x;

    return true;
}

bool PlaylistChooser::touchEnded( ci::app::TouchEvent::Touch touch )
{
    if (mData == NULL) return false;

	mIsDragging		= false;

    mTouchPos		= globalToLocal( touch.getPos() );
    mOffsetX		= mTouchDragStartOffset + (mTouchPos.x - mTouchDragStartPos.x);

    if (mTouchDragPlaylistIndex >= 0) {

        float movement	= mTouchDragStartPos.distance( mTouchPos );
        if (movement < 15.0f) {
            // TODO: also measure time and don't allow long selection gaps
            mCurrentIndex = mTouchDragPlaylistIndex;
            mPrevIndex = mCurrentIndex; // set this so that we won't fire the callback twice
            mCbPlaylistSelected.call( mData->mPlaylists[mTouchDragPlaylistIndex] );
            mCbPlaylistTouched.call( mData->mPlaylists[mTouchDragPlaylistIndex] );
        }
    }

    mTouchDragId			= 0;
    mTouchDragPlaylistIndex = -1;
    mTouchDragStartPos		= mTouchPos;
    mTouchDragStartOffset	= mOffsetX;

    return true;
}

void PlaylistChooser::update()
{
    if (mData == NULL) return;

    mInterfaceSize  = getRoot()->getInterfaceSize();

    // update full rect for layout, hit testing etc.
    mFullRect.set( 0, 0, mInterfaceSize.x, mStartY + mFontHeight + mStartY );

    // total size of all playlist labels + spaces
    float totalWidth = (mPlaylistSize.x * mNumPlaylists) + (mSpacerWidth * (mNumPlaylists+1));
    float maxOffsetX = 0.0f;
    float minOffsetX = 0.0f;

    if ( totalWidth < mInterfaceSize.x) {
        maxOffsetX = mInterfaceSize.x - totalWidth;
    }
    else {
        minOffsetX = mInterfaceSize.x - totalWidth;
    }

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

	if( !mIsDragging ){
        // carry on with inertia/momentum scrolling
		mOffsetX += mTouchVel;

        // spring back if we've gone too far
		if( mOffsetX < minOffsetX ){
			mTouchVel = 0.0f;
			mOffsetX += ( minOffsetX - mOffsetX ) * 0.2f;
		}
        else if( mOffsetX > maxOffsetX ){
			mTouchVel = 0.0f;
			mOffsetX += ( maxOffsetX - mOffsetX ) * 0.2f;
		}

        if( abs( mTouchVel ) > 1.0f ) {
            // slow down if we're moving fast:
            mTouchVel *= 0.95f;
        }
        else {
            // otherwise we're slow enough to think again
            // so cancel momentum completely:
			mTouchVel		 = 0.0f;
		}
	}

    ////////// update placement rects

    mPlaylistRects.clear();

    const float y  = mStartY;
    const float h  = mFontHeight;

    float xPos = mOffsetX + mSpacerWidth;

    for( int i = 0; i < mNumPlaylists; i++ )
	{
        if( xPos < mInterfaceSize.x && xPos + mPlaylistSize.x > 0.0f )
		{
			if (!mTextures[i]) {
				makeTexture( i, mData->mPlaylists[i] );
            }
            // put texture rect at center of playlist rect
			const float cx = xPos + mPlaylistSize.x * 0.5f;
			const float w2 = mTextures[i].getWidth() * 0.5f;
			mPlaylistRects.push_back( RectRef( new Rectf( cx - w2, y, cx + w2, y + h ) ) );
        }
        else {
			mPlaylistRects.push_back( RectRef() );
		}

        xPos += mSpacerWidth + mPlaylistSize.x;
    }
}

void PlaylistChooser::draw()
{
	if( mData == NULL ) return;

	gl::disableDepthRead();
	gl::disableDepthWrite();
	gl::enableAlphaBlending();
	gl::enableAdditiveBlending();

    float r = BRIGHT_BLUE.r;
    float g = BRIGHT_BLUE.g;
    float b = BRIGHT_BLUE.b;
    // opacity is supplied by UiLayer::draw

    gl::color( ColorA( r, g, b, mOpacity * 0.125f ) );
    gl::drawLine( Vec2f(0,0), Vec2f(mInterfaceSize.x,0) );

//    float xPos = mOffsetX + mSpacerWidth;

    for( int i = 0; i < mNumPlaylists; i++ )
	{
        RectRef rect = mPlaylistRects[i];
        if( rect && rect->x1 < mInterfaceSize.x && rect->x2 > 0.0f )
        {
            if ( i == mCurrentIndex ) {
                gl::color( ColorA( BRIGHT_BLUE, mOpacity ) );
            }
            else if ( i == mTouchDragPlaylistIndex ) {
                gl::color( ColorA( 1, 1, 1, mOpacity ) );
            }
            else {
                gl::color( ColorA( BLUE, mOpacity ) );
            }

            gl::draw( mTextures[i], rect->getUpperLeft() );

//            gl::color( Color::white() );
//            gl::drawStrokedRect( *rect );
        }

//        gl::color( Color::white() );
//        gl::drawStrokedRect( Rectf( xPos, mStartY, xPos + mPlaylistSize.x, mStartY + mFontHeight ) );
//
//        xPos += mPlaylistSize.x + mSpacerWidth;
    }

//    Rectf center( (mInterfaceSize.x - mPlaylistSize.x) / 2.0f, 0.0f,
//                  (mInterfaceSize.x + mPlaylistSize.x) / 2.0f, mFullRect.getHeight() );
//
//    gl::color( ColorA( BRIGHT_BLUE, alpha * 0.15f ) );
//    gl::drawSolidRect( center );
//
//    gl::color( ColorA( BRIGHT_BLUE, alpha * 0.5f ) );
//    gl::drawSolidRect( Rectf( center.x1, center.y1 + 0.0f, center.x2, center.y1 + 3.0f ) );
//    gl::drawSolidRect( Rectf( center.x1, center.y2 - 3.0f, center.x2, center.y2 - 0.0f ) );

	gl::disableDepthRead();
	gl::disableDepthWrite();
	gl::enableAlphaBlending();
}

void PlaylistChooser::makeTexture( int index, ipod::PlaylistRef playlist )
{
    // FIXME: measure the texture and shorten the name if needed
	string name = playlist->getPlaylistName();
	if( name.length() > 19 ){
		name = name.substr( 0, 18 );
		name += "...";
	}
	TextLayout layout;
	layout.setFont( mFont );
	layout.setColor( Color::white() );
	layout.addLine( name );
	mTextures[index] = gl::Texture( layout.render( true, false ) );
}

float PlaylistChooser::getAlpha( float x )
{
	float per		= x / mInterfaceSize.x;
	float invCos	= ( 1.0f - (float)cos( per * TWO_PI ) ) * 0.5f;
	float cosPer	= pow( invCos, 0.5f );
	return cosPer;
}

void PlaylistChooser::setDataWorldCam( Data *data, World *world, CameraPersp *cam )
{
    mData			= data;
    mWorld			= world;
    mCam			= cam;
	mNumPlaylists	= mData->mPlaylists.size();
    mTextures.resize(mNumPlaylists);
}

float PlaylistChooser::getHeight()
{
    return mFullRect.getHeight();
}

<|endoftext|>