<commit_before>
#include "GLTexture.h"
#include "Image.h"
#include "GLDriver.h"
#include "GLTypeMappings.h"

namespace Demi
{
    DiGLTextureDrv::DiGLTextureDrv(DiTexture* parent)
        :mGLFormat(GL_NONE),
        mGLTextureType(GL_TEXTURE_2D),
        mTextureID(0),
        mImageSize(0),
        mBuffer(nullptr),
        mCurrentLockFlag(LOCK_NORMAL)
    {
    }

    DiGLTextureDrv::~DiGLTextureDrv()
    {
        if (mBuffer->data)
        {
            delete[] (uint8*)mBuffer->data;
            mBuffer->data = nullptr;
        }
    }

    void DiGLTextureDrv::CopyToMemory(const DiBox &srcBox, const DiPixelBox &dst)
    {
    }

    void DiGLTextureDrv::Release()
    {
        glDeleteTextures(1, &mTextureID);
        if (mBuffer)
        {
            DI_DELETE mBuffer;
            mBuffer = nullptr;
        }
    }

    void DiGLTextureDrv::CreateTexture()
    {
        uint32 width = mParent->GetWidth();
        uint32 height = mParent->GetHeight();
        uint32 numLevels = mParent->GetNumLevels();
        DiPixelFormat fmt = mParent->GetFormat();

        mBuffer = DI_NEW DiPixelBox(width, height, fmt);

        mGLFormat = DiGLTypeMappings::GLFormatMapping[fmt];
        if (mGLFormat == GL_NONE)
        {
            DI_WARNING("Unsupported pixel format: %d", fmt);
            return;
        }

        glGenTextures(1, &mTextureID);

        mGLTextureType = DiGLTypeMappings::GetGLTextureType(mParent->GetTextureType());
        glBindTexture(mGLTextureType, mTextureID);

        if (GLEW_VERSION_1_2)
            glTexParameteri(mGLTextureType, GL_TEXTURE_MAX_LEVEL, numLevels);

        glTexParameteri(mGLTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(mGLTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        if (GLEW_VERSION_1_2)
        {
            glTexParameteri(mGLTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(mGLTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        }

        mImageSize = DiPixelBox::ComputeImageByteSize(width, height, fmt);

        // TODO: Auto generate mipmap

        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);
        if (isCompressed)
        {
            uint32 imageSize = mImageSize;

            uint8 *tmpdata = new uint8[imageSize];
            memset(tmpdata, 0, imageSize);

            for (size_t i = 0; i < numLevels; i++)
            {
                imageSize = DiPixelBox::ComputeImageByteSize(width, height, fmt);
                switch (mGLTextureType)
                {
                case GL_TEXTURE_2D:
                    glCompressedTexImage2DARB(GL_TEXTURE_2D, i, mGLFormat,
                        width, height, 0, imageSize, tmpdata);
                    break;
                case GL_TEXTURE_CUBE_MAP:
                    for (int face = 0; face < 6; face++)
                    {
                        glCompressedTexImage2DARB(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, mGLFormat,
                            width, height, 0, imageSize, tmpdata);
                    }
                    break;
                }
                if (width > 1) width = width / 2;
                if (height > 1) height = height / 2;
            }

            delete[] tmpdata;
        }
        else
        {
            for (size_t i = 0; i < numLevels; i++)
            {
                switch (mGLTextureType)
                {
                case GL_TEXTURE_2D:
                    glTexImage2D(GL_TEXTURE_2D, i, mGLFormat,
                        width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
                    break;
                case GL_TEXTURE_CUBE_MAP:
                    for (int face = 0; face < 6; face++)
                    {
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, mGLFormat,
                            width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
                    }
                    break;
                }
                if (width > 1) width = width / 2;
                if (height > 1) height = height / 2;
            }
        }
    }

    void DiGLTextureDrv::Bind(uint32 samplerIndex)
    {
        if (!mTextureID)
        {
            glBindTexture(mGLTextureType, 0);
        }
        else
        {
            glEnable(mGLTextureType);
            glBindTexture(mGLTextureType, mTextureID);
        }
    }

    void* DiGLTextureDrv::LockLevel(uint32 level, uint32 surface, DiLockFlag lockflag)
    {
        DiBox lockbox(0, 0, mBuffer->GetWidth(), mBuffer->GetHeight());

        AllocateBuffer();

        mCurrentLockFlag = lockflag;
        if (lockflag != LOCK_DISCARD)
        {
            Download(*mBuffer, level, surface);
        }

        return mBuffer->data;
    }

    void DiGLTextureDrv::UnlockLevel(uint32 level, uint32 surface)
    {
        if (mCurrentLockFlag != LOCK_READ_ONLY)
        {
            DiBox lockbox(0, 0, mBuffer->GetWidth(), mBuffer->GetHeight());
            Upload(*mBuffer, lockbox, level, surface);
        }
        DeallocateBuffer();
    }

    void* DiGLTextureDrv::GetSurfaceHandle()
    {
        return nullptr;
    }

    void DiGLTextureDrv::CopyFromMemory(const DiPixelBox &srcBox, const DiBox &dst, uint32 level, uint32 surface /*= 0*/)
    {
        AllocateBuffer();
        Upload(srcBox, dst, level, surface);
        DeallocateBuffer();
    }

    void DiGLTextureDrv::AllocateBuffer()
    {
        if (!mBuffer->data)
        {
            mBuffer->data = DI_NEW uint8[mImageSize];
        }
    }

    void DiGLTextureDrv::DeallocateBuffer()
    {
        if (mParent->GetResourceUsage() & RU_STATIC)
        {
            delete[] (uint8*)mBuffer->data;
            mBuffer->data = nullptr;
        }
    }

    void DiGLTextureDrv::Upload(const DiPixelBox &src, const DiBox &dst, uint32 level, uint32 surface)
    {
        glBindTexture(mGLTextureType, mTextureID);

        DiPixelFormat fmt = mParent->GetFormat();
        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);

        GLenum faceType = GL_TEXTURE_2D;
        if (mGLTextureType == GL_TEXTURE_CUBE_MAP)
            faceType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + surface;

        if (isCompressed)
        {
            switch (mGLTextureType)
            {
            case GL_TEXTURE_2D:
            case GL_TEXTURE_CUBE_MAP:
                if (dst.left == 0 && dst.top == 0)
                {
                    glCompressedTexImage2DARB(faceType, level,
                        mGLFormat,
                        dst.GetWidth(),
                        dst.GetHeight(),
                        0,
                        src.GetConsecutiveSize(),
                        src.data);
                }
                else
                {
                    glCompressedTexSubImage2DARB(faceType, level,
                        dst.left, dst.top,
                        dst.GetWidth(), dst.GetHeight(),
                        mGLFormat, src.GetConsecutiveSize(),
                        src.data);
                }
                break;
            }
        }
        else
        {
            if (src.GetWidth() != src.rowPitch)
                glPixelStorei(GL_UNPACK_ROW_LENGTH, src.rowPitch);
            if (src.GetWidth() > 0 && src.GetHeight()*src.GetWidth() != src.slicePitch)
                glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (src.slicePitch / src.GetWidth()));
            if (src.left > 0 || src.top > 0)
                glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.left + src.rowPitch * src.top);
            if ((src.GetWidth()*DiPixelBox::GetNumElemBytes(src.format)) & 3) {
                // Standard alignment of 4 is not right
                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
            }
            switch (mGLTextureType)
            {
            case GL_TEXTURE_2D:
            case GL_TEXTURE_CUBE_MAP:
                glTexSubImage2D(faceType, level,
                    dst.left, dst.top,
                    dst.GetWidth(), dst.GetHeight(),
                    mGLFormat, mGLFormat,
                    src.data);
                break;
            }
        }

        // restore
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        if (GLEW_VERSION_1_2)
            glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    }

    void DiGLTextureDrv::Download(const DiPixelBox &data, uint32 level, uint32 surface)
    {
        if (data.GetWidth() != mParent->GetWidth() ||
            data.GetHeight() != mParent->GetHeight())
        {
            DI_WARNING("Only download of entire buffer of the texture is supported.");
            return;
        }

        glBindTexture(mGLTextureType, mTextureID);

        DiPixelFormat fmt = mParent->GetFormat();
        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);

        GLenum faceType = GL_TEXTURE_2D;
        if (mGLTextureType == GL_TEXTURE_CUBE_MAP)
            faceType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + surface;

        if (isCompressed)
        {
            glGetCompressedTexImageARB(faceType, level, data.data);
        }
        else
        {
            if (data.GetWidth() != data.rowPitch)
                glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch);
            if (data.GetHeight()*data.GetWidth() != data.slicePitch)
                glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch / data.GetWidth()));
            if (data.left > 0 || data.top > 0)
                glPixelStorei(GL_PACK_SKIP_PIXELS, data.left + data.rowPitch * data.top);
            if ((data.GetWidth()*DiPixelBox::GetNumElemBytes(data.format)) & 3) {
                // Standard alignment of 4 is not right
                glPixelStorei(GL_PACK_ALIGNMENT, 1);
            }
            // We can only get the entire texture
            glGetTexImage(faceType, level, mGLFormat, mGLFormat, data.data);
            // Restore defaults
            glPixelStorei(GL_PACK_ROW_LENGTH, 0);
            glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
            glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
            glPixelStorei(GL_PACK_ALIGNMENT, 4);
        }
    }
}<commit_msg>CopyToMemory<commit_after>
#include "GLTexture.h"
#include "Image.h"
#include "GLDriver.h"
#include "GLTypeMappings.h"

namespace Demi
{
    DiGLTextureDrv::DiGLTextureDrv(DiTexture* parent)
        :mGLFormat(GL_NONE),
        mGLTextureType(GL_TEXTURE_2D),
        mTextureID(0),
        mImageSize(0),
        mBuffer(nullptr),
        mCurrentLockFlag(LOCK_NORMAL)
    {
    }

    DiGLTextureDrv::~DiGLTextureDrv()
    {
        if (mBuffer->data)
        {
            delete[] (uint8*)mBuffer->data;
            mBuffer->data = nullptr;
        }
    }

    void DiGLTextureDrv::CopyToMemory(const DiBox &srcBox, const DiPixelBox &dst)
    {
        DI_ASSERT(mBuffer);
        if (!mBuffer->Contains(srcBox))
        {
            DI_WARNING("Source box out of range.");
            return;
        }

        if (mBuffer->GetWidth() != srcBox.GetWidth() || mBuffer->GetHeight() != srcBox.GetHeight())
        {
            DI_WARNING("No scale is supported currently.");
            return;
        }

        Download(dst,0,0);
    }

    void DiGLTextureDrv::Release()
    {
        glDeleteTextures(1, &mTextureID);
        if (mBuffer)
        {
            DI_DELETE mBuffer;
            mBuffer = nullptr;
        }
    }

    void DiGLTextureDrv::CreateTexture()
    {
        uint32 width = mParent->GetWidth();
        uint32 height = mParent->GetHeight();
        uint32 numLevels = mParent->GetNumLevels();
        DiPixelFormat fmt = mParent->GetFormat();

        mBuffer = DI_NEW DiPixelBox(width, height, fmt);

        mGLFormat = DiGLTypeMappings::GLFormatMapping[fmt];
        if (mGLFormat == GL_NONE)
        {
            DI_WARNING("Unsupported pixel format: %d", fmt);
            return;
        }

        glGenTextures(1, &mTextureID);

        mGLTextureType = DiGLTypeMappings::GetGLTextureType(mParent->GetTextureType());
        glBindTexture(mGLTextureType, mTextureID);

        if (GLEW_VERSION_1_2)
            glTexParameteri(mGLTextureType, GL_TEXTURE_MAX_LEVEL, numLevels);

        glTexParameteri(mGLTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(mGLTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        if (GLEW_VERSION_1_2)
        {
            glTexParameteri(mGLTextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(mGLTextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        }

        mImageSize = DiPixelBox::ComputeImageByteSize(width, height, fmt);

        // TODO: Auto generate mipmap

        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);
        if (isCompressed)
        {
            uint32 imageSize = mImageSize;

            uint8 *tmpdata = new uint8[imageSize];
            memset(tmpdata, 0, imageSize);

            for (size_t i = 0; i < numLevels; i++)
            {
                imageSize = DiPixelBox::ComputeImageByteSize(width, height, fmt);
                switch (mGLTextureType)
                {
                case GL_TEXTURE_2D:
                    glCompressedTexImage2DARB(GL_TEXTURE_2D, i, mGLFormat,
                        width, height, 0, imageSize, tmpdata);
                    break;
                case GL_TEXTURE_CUBE_MAP:
                    for (int face = 0; face < 6; face++)
                    {
                        glCompressedTexImage2DARB(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, mGLFormat,
                            width, height, 0, imageSize, tmpdata);
                    }
                    break;
                }
                if (width > 1) width = width / 2;
                if (height > 1) height = height / 2;
            }

            delete[] tmpdata;
        }
        else
        {
            for (size_t i = 0; i < numLevels; i++)
            {
                switch (mGLTextureType)
                {
                case GL_TEXTURE_2D:
                    glTexImage2D(GL_TEXTURE_2D, i, mGLFormat,
                        width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
                    break;
                case GL_TEXTURE_CUBE_MAP:
                    for (int face = 0; face < 6; face++)
                    {
                        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, mGLFormat,
                            width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
                    }
                    break;
                }
                if (width > 1) width = width / 2;
                if (height > 1) height = height / 2;
            }
        }
    }

    void DiGLTextureDrv::Bind(uint32 samplerIndex)
    {
        if (!mTextureID)
        {
            glBindTexture(mGLTextureType, 0);
        }
        else
        {
            glEnable(mGLTextureType);
            glBindTexture(mGLTextureType, mTextureID);
        }
    }

    void* DiGLTextureDrv::LockLevel(uint32 level, uint32 surface, DiLockFlag lockflag)
    {
        DiBox lockbox(0, 0, mBuffer->GetWidth(), mBuffer->GetHeight());

        AllocateBuffer();

        mCurrentLockFlag = lockflag;
        if (lockflag != LOCK_DISCARD)
        {
            Download(*mBuffer, level, surface);
        }

        return mBuffer->data;
    }

    void DiGLTextureDrv::UnlockLevel(uint32 level, uint32 surface)
    {
        if (mCurrentLockFlag != LOCK_READ_ONLY)
        {
            DiBox lockbox(0, 0, mBuffer->GetWidth(), mBuffer->GetHeight());
            Upload(*mBuffer, lockbox, level, surface);
        }
        DeallocateBuffer();
    }

    void* DiGLTextureDrv::GetSurfaceHandle()
    {
        return nullptr;
    }

    void DiGLTextureDrv::CopyFromMemory(const DiPixelBox &srcBox, const DiBox &dst, uint32 level, uint32 surface /*= 0*/)
    {
        AllocateBuffer();
        Upload(srcBox, dst, level, surface);
        DeallocateBuffer();
    }

    void DiGLTextureDrv::AllocateBuffer()
    {
        if (!mBuffer->data)
        {
            mBuffer->data = DI_NEW uint8[mImageSize];
        }
    }

    void DiGLTextureDrv::DeallocateBuffer()
    {
        if (mParent->GetResourceUsage() & RU_STATIC)
        {
            delete[] (uint8*)mBuffer->data;
            mBuffer->data = nullptr;
        }
    }

    void DiGLTextureDrv::Upload(const DiPixelBox &src, const DiBox &dst, uint32 level, uint32 surface)
    {
        glBindTexture(mGLTextureType, mTextureID);

        DiPixelFormat fmt = mParent->GetFormat();
        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);

        GLenum faceType = GL_TEXTURE_2D;
        if (mGLTextureType == GL_TEXTURE_CUBE_MAP)
            faceType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + surface;

        if (isCompressed)
        {
            switch (mGLTextureType)
            {
            case GL_TEXTURE_2D:
            case GL_TEXTURE_CUBE_MAP:
                if (dst.left == 0 && dst.top == 0)
                {
                    glCompressedTexImage2DARB(faceType, level,
                        mGLFormat,
                        dst.GetWidth(),
                        dst.GetHeight(),
                        0,
                        src.GetConsecutiveSize(),
                        src.data);
                }
                else
                {
                    glCompressedTexSubImage2DARB(faceType, level,
                        dst.left, dst.top,
                        dst.GetWidth(), dst.GetHeight(),
                        mGLFormat, src.GetConsecutiveSize(),
                        src.data);
                }
                break;
            }
        }
        else
        {
            if (src.GetWidth() != src.rowPitch)
                glPixelStorei(GL_UNPACK_ROW_LENGTH, src.rowPitch);
            if (src.GetWidth() > 0 && src.GetHeight()*src.GetWidth() != src.slicePitch)
                glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, (src.slicePitch / src.GetWidth()));
            if (src.left > 0 || src.top > 0)
                glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.left + src.rowPitch * src.top);
            if ((src.GetWidth()*DiPixelBox::GetNumElemBytes(src.format)) & 3) {
                // Standard alignment of 4 is not right
                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
            }
            switch (mGLTextureType)
            {
            case GL_TEXTURE_2D:
            case GL_TEXTURE_CUBE_MAP:
                glTexSubImage2D(faceType, level,
                    dst.left, dst.top,
                    dst.GetWidth(), dst.GetHeight(),
                    mGLFormat, mGLFormat,
                    src.data);
                break;
            }
        }

        // restore
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        if (GLEW_VERSION_1_2)
            glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    }

    void DiGLTextureDrv::Download(const DiPixelBox &data, uint32 level, uint32 surface)
    {
        if (data.GetWidth() != mParent->GetWidth() ||
            data.GetHeight() != mParent->GetHeight())
        {
            DI_WARNING("Only download of entire buffer of the texture is supported.");
            return;
        }

        glBindTexture(mGLTextureType, mTextureID);

        DiPixelFormat fmt = mParent->GetFormat();
        BOOL isCompressed = DiPixelBox::IsCompressedFormat(fmt);

        GLenum faceType = GL_TEXTURE_2D;
        if (mGLTextureType == GL_TEXTURE_CUBE_MAP)
            faceType = GL_TEXTURE_CUBE_MAP_POSITIVE_X + surface;

        if (isCompressed)
        {
            glGetCompressedTexImageARB(faceType, level, data.data);
        }
        else
        {
            if (data.GetWidth() != data.rowPitch)
                glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch);
            if (data.GetHeight()*data.GetWidth() != data.slicePitch)
                glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch / data.GetWidth()));
            if (data.left > 0 || data.top > 0)
                glPixelStorei(GL_PACK_SKIP_PIXELS, data.left + data.rowPitch * data.top);
            if ((data.GetWidth()*DiPixelBox::GetNumElemBytes(data.format)) & 3) {
                // Standard alignment of 4 is not right
                glPixelStorei(GL_PACK_ALIGNMENT, 1);
            }
            // We can only get the entire texture
            glGetTexImage(faceType, level, mGLFormat, mGLFormat, data.data);
            // Restore defaults
            glPixelStorei(GL_PACK_ROW_LENGTH, 0);
            glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
            glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
            glPixelStorei(GL_PACK_ALIGNMENT, 4);
        }
    }
}<|endoftext|>


<commit_before>#include "libtorrent/upnp.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/connection_queue.hpp"
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/intrusive_ptr.hpp>

using namespace libtorrent;

void callback(int tcp, int udp, std::string const& err)
{
	std::cerr << "tcp: " << tcp << ", udp: " << udp << ", error: \"" << err << "\"\n";
}

int main(int argc, char* argv[])
{
	io_service ios;
	std::string user_agent = "test agent";

	if (argc != 3)
	{
		std::cerr << "usage: " << argv[0] << " tcp-port udp-port" << std::endl;
		return 1;
	}

	connection_queue cc(ios);
	boost::intrusive_ptr<upnp> upnp_handler = new upnp(ios, cc, address_v4(), user_agent, &callback);

	deadline_timer timer(ios);
	timer.expires_from_now(seconds(2));
	timer.async_wait(boost::bind(&io_service::stop, boost::ref(ios)));

	std::cerr << "broadcasting for UPnP device" << std::endl;

	ios.reset();
	ios.run();

	upnp_handler->set_mappings(atoi(argv[1]), atoi(argv[2]));
	timer.expires_from_now(seconds(5));
	timer.async_wait(boost::bind(&io_service::stop, boost::ref(ios)));
	std::cerr << "mapping ports TCP: " << argv[1]
		<< " UDP: " << argv[2] << std::endl;

	ios.reset();
	ios.run();
	std::cerr << "removing mappings" << std::endl;
	upnp_handler->close();

	ios.reset();
	ios.run();
	std::cerr << "closing" << std::endl;
}

<commit_msg>fixed test_upnp<commit_after>#include "libtorrent/upnp.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/connection_queue.hpp"
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/intrusive_ptr.hpp>

using namespace libtorrent;

void callback(int tcp, int udp, std::string const& err)
{
	std::cerr << "tcp: " << tcp << ", udp: " << udp << ", error: \"" << err << "\"\n";
}

int main(int argc, char* argv[])
{
	io_service ios;
	std::string user_agent = "test agent";

	if (argc != 3)
	{
		std::cerr << "usage: " << argv[0] << " tcp-port udp-port" << std::endl;
		return 1;
	}

	connection_queue cc(ios);
	boost::intrusive_ptr<upnp> upnp_handler = new upnp(ios, cc, address_v4(), user_agent, &callback);
	upnp_handler->discover_device();

	deadline_timer timer(ios);
	timer.expires_from_now(seconds(2));
	timer.async_wait(boost::bind(&io_service::stop, boost::ref(ios)));

	std::cerr << "broadcasting for UPnP device" << std::endl;

	ios.reset();
	ios.run();

	upnp_handler->set_mappings(atoi(argv[1]), atoi(argv[2]));
	timer.expires_from_now(seconds(5));
	timer.async_wait(boost::bind(&io_service::stop, boost::ref(ios)));
	std::cerr << "mapping ports TCP: " << argv[1]
		<< " UDP: " << argv[2] << std::endl;

	ios.reset();
	ios.run();
	std::cerr << "router: " << upnp_handler->router_model() << std::endl;
	std::cerr << "removing mappings" << std::endl;
	upnp_handler->close();

	ios.reset();
	ios.run();
	std::cerr << "closing" << std::endl;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2014, Arvid Norberg
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 author 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 "test.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/ConvertUTF.h"
#include "setup_transfer.hpp" // for load_file
#include "libtorrent/file.hpp" // for combine_path

#include <vector>

using namespace libtorrent;

int test_main()
{
	std::vector<char> utf8_source;
	error_code ec;
	load_file(combine_path("..", "utf8_test.txt"), utf8_source, ec, 1000000);
	if (ec) fprintf(stderr, "failed to open file: (%d) %s\n", ec.value()
		, ec.message().c_str());
	TEST_CHECK(!ec);

	// test lower level conversions

	// utf8 -> utf16 -> utf32 -> utf8
	{
		std::vector<UTF16> utf16(utf8_source.size());
		UTF8 const* in8 = (UTF8 const*)&utf8_source[0];
		UTF16* out16 = &utf16[0];
		ConversionResult ret = ConvertUTF8toUTF16(&in8, in8 + utf8_source.size()
			, &out16, out16 + utf16.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);

		std::vector<UTF32> utf32(utf8_source.size());
		UTF16 const* in16 = &utf16[0];
		UTF32* out32 = &utf32[0];
		ret = ConvertUTF16toUTF32(&in16, out16
			, &out32, out32 + utf32.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);

		std::vector<UTF8> utf8(utf8_source.size());
		UTF32 const* in32 = &utf32[0];
		UTF8* out8 = &utf8[0];
		ret = ConvertUTF32toUTF8(&in32, out32
			, &out8, out8 + utf8.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		TEST_EQUAL(out8 - &utf8[0], utf8_source.size());
		TEST_CHECK(std::equal(&utf8[0], out8, (UTF8 const*)&utf8_source[0]));
	}

	// utf8 -> utf32 -> utf16 -> utf8
	{
		std::vector<UTF32> utf32(utf8_source.size());
		UTF8 const* in8 = (UTF8 const*)&utf8_source[0];
		UTF32* out32 = &utf32[0];
		ConversionResult ret = ConvertUTF8toUTF32(&in8, in8 + utf8_source.size()
			, &out32, out32 + utf32.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);

		std::vector<UTF16> utf16(utf8_source.size());
		UTF32 const* in32 = &utf32[0];
		UTF16* out16 = &utf16[0];
		ret = ConvertUTF32toUTF16(&in32, out32
			, &out16, out16 + utf16.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);

		std::vector<UTF8> utf8(utf8_source.size());
		UTF16 const* in16 = &utf16[0];
		UTF8* out8 = &utf8[0];
		ret = ConvertUTF16toUTF8(&in16, out16
			, &out8, out8 + utf8.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		TEST_EQUAL(out8 - &utf8[0], utf8_source.size());
		TEST_CHECK(std::equal(&utf8[0], out8, (UTF8 const*)&utf8_source[0]));
	}

	// test higher level conversions

	std::string utf8;
	std::copy(utf8_source.begin(), utf8_source.end(), std::back_inserter(utf8));

	std::wstring wide;
	utf8_conv_result_t ret = utf8_wchar(utf8, wide);
	TEST_EQUAL(ret, conversion_ok);

	std::string identity;
	ret = wchar_utf8(wide, identity);
	TEST_EQUAL(ret, conversion_ok);

	TEST_EQUAL(utf8, identity);
	return 0;
}

<commit_msg>extend utf8 unit test<commit_after>/*

Copyright (c) 2014, Arvid Norberg
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 author 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 "test.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/ConvertUTF.h"
#include "setup_transfer.hpp" // for load_file
#include "libtorrent/file.hpp" // for combine_path

#include <vector>

using namespace libtorrent;

void verify_transforms(char const* utf8_source, int utf8_source_len = -1)
{
	if (utf8_source_len == -1)
		utf8_source_len = strlen(utf8_source);

	// utf8 -> utf16 -> utf32 -> utf8
	{
		std::vector<UTF16> utf16(utf8_source_len);
		UTF8 const* in8 = (UTF8 const*)utf8_source;
		UTF16* out16 = &utf16[0];
		ConversionResult ret = ConvertUTF8toUTF16(&in8, in8 + utf8_source_len
			, &out16, out16 + utf16.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		std::vector<UTF32> utf32(utf8_source_len);
		UTF16 const* in16 = &utf16[0];
		UTF32* out32 = &utf32[0];
		ret = ConvertUTF16toUTF32(&in16, out16
			, &out32, out32 + utf32.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		std::vector<UTF8> utf8(utf8_source_len);
		UTF32 const* in32 = &utf32[0];
		UTF8* out8 = &utf8[0];
		ret = ConvertUTF32toUTF8(&in32, out32
			, &out8, out8 + utf8.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		TEST_EQUAL(out8 - &utf8[0], utf8_source_len);
		TEST_CHECK(std::equal(&utf8[0], out8, (UTF8 const*)utf8_source));
	}

	// utf8 -> utf32 -> utf16 -> utf8
	{
		std::vector<UTF32> utf32(utf8_source_len);
		UTF8 const* in8 = (UTF8 const*)utf8_source;
		UTF32* out32 = &utf32[0];
		ConversionResult ret = ConvertUTF8toUTF32(&in8, in8 + utf8_source_len
			, &out32, out32 + utf32.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		std::vector<UTF16> utf16(utf8_source_len);
		UTF32 const* in32 = &utf32[0];
		UTF16* out16 = &utf16[0];
		ret = ConvertUTF32toUTF16(&in32, out32
			, &out16, out16 + utf16.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		std::vector<UTF8> utf8(utf8_source_len);
		UTF16 const* in16 = &utf16[0];
		UTF8* out8 = &utf8[0];
		ret = ConvertUTF16toUTF8(&in16, out16
			, &out8, out8 + utf8.size(), strictConversion);

		TEST_EQUAL(ret, conversionOK);
		if (ret != conversionOK && utf8_source_len < 10)
		{
			for (char const* i = utf8_source; *i != 0; ++i)
				fprintf(stderr, "%x ", UTF8(*i));
		}

		TEST_EQUAL(out8 - &utf8[0], utf8_source_len);
		TEST_CHECK(std::equal(&utf8[0], out8, (UTF8 const*)utf8_source));
	}
}

void expect_error(char const* utf8, ConversionResult expect)
{
	UTF8 const* in8 = (UTF8 const*)utf8;
	std::vector<UTF32> utf32(strlen(utf8));
	UTF32* out32 = &utf32[0];
	ConversionResult ret = ConvertUTF8toUTF32(&in8, in8 + strlen(utf8)
		, &out32, out32 + utf32.size(), strictConversion);

	TEST_EQUAL(ret, expect);
	if (ret != expect)
	{
		fprintf(stderr, "%d expected %d\n", ret, expect);
		for (char const* i = utf8; *i != 0; ++i)
			fprintf(stderr, "%x ", UTF8(*i));
	}

	in8 = (UTF8 const*)utf8;
	std::vector<UTF16> utf16(strlen(utf8));
	UTF16* out16 = &utf16[0];
	ret = ConvertUTF8toUTF16(&in8, in8 + strlen(utf8)
		, &out16, out16 + utf16.size(), strictConversion);

	TEST_EQUAL(ret, expect);
	if (ret != expect)
	{
		fprintf(stderr, "%d expected %d\n", ret, expect);
		for (char const* i = utf8; *i != 0; ++i)
			fprintf(stderr, "%x ", UTF8(*i));
	}
}

int test_main()
{
	std::vector<char> utf8_source;
	error_code ec;
	load_file(combine_path("..", "utf8_test.txt"), utf8_source, ec, 1000000);
	if (ec) fprintf(stderr, "failed to open file: (%d) %s\n", ec.value()
		, ec.message().c_str());
	TEST_CHECK(!ec);

	// test lower level conversions

	verify_transforms(&utf8_source[0], utf8_source.size());

	verify_transforms("\xc3\xb0");
	verify_transforms("\xed\x9f\xbf");
	verify_transforms("\xee\x80\x80");
	verify_transforms("\xef\xbf\xbd");
	verify_transforms("\xf4\x8f\xbf\xbf");
	verify_transforms("\xf0\x91\x80\x80\x30");

	// Unexpected continuation bytes
	expect_error("\x80", sourceIllegal);
	expect_error("\xbf", sourceIllegal);

	// Impossible bytes
	// The following two bytes cannot appear in a correct UTF-8 string
	expect_error("\xff", sourceExhausted);
	expect_error("\xfe", sourceExhausted);
	expect_error("\xff\xff\xfe\xfe", sourceExhausted);

	// Examples of an overlong ASCII character
	expect_error("\xc0\xaf", sourceIllegal);
	expect_error("\xe0\x80\xaf", sourceIllegal);
	expect_error("\xf0\x80\x80\xaf", sourceIllegal);
	expect_error("\xf8\x80\x80\x80\xaf ", sourceIllegal);
	expect_error("\xfc\x80\x80\x80\x80\xaf", sourceIllegal);

	// Maximum overlong sequences
	expect_error("\xc1\xbf", sourceIllegal);
	expect_error("\xe0\x9f\xbf", sourceIllegal);
	expect_error("\xf0\x8f\xbf\xbf", sourceIllegal);
	expect_error("\xf8\x87\xbf\xbf\xbf", sourceIllegal);
	expect_error("\xfc\x83\xbf\xbf\xbf\xbf", sourceIllegal);

	// Overlong representation of the NUL character
	expect_error("\xc0\x80", sourceIllegal);
	expect_error("\xe0\x80\x80", sourceIllegal);
	expect_error("\xf0\x80\x80\x80", sourceIllegal);
	expect_error("\xf8\x80\x80\x80\x80", sourceIllegal);
	expect_error("\xfc\x80\x80\x80\x80\x80", sourceIllegal);

	// Single UTF-16 surrogates
	expect_error("\xed\xa0\x80", sourceIllegal);
	expect_error("\xed\xad\xbf", sourceIllegal);
	expect_error("\xed\xae\x80", sourceIllegal);
	expect_error("\xed\xaf\xbf", sourceIllegal);
	expect_error("\xed\xb0\x80", sourceIllegal);
	expect_error("\xed\xbe\x80", sourceIllegal);
	expect_error("\xed\xbf\xbf", sourceIllegal);

	// Paired UTF-16 surrogates
	expect_error("\xed\xa0\x80\xed\xb0\x80", sourceIllegal);
	expect_error("\xed\xa0\x80\xed\xbf\xbf", sourceIllegal);
	expect_error("\xed\xad\xbf\xed\xb0\x80", sourceIllegal);
	expect_error("\xed\xad\xbf\xed\xbf\xbf", sourceIllegal);
	expect_error("\xed\xae\x80\xed\xb0\x80", sourceIllegal);
	expect_error("\xed\xae\x80\xed\xbf\xbf", sourceIllegal);
	expect_error("\xed\xaf\xbf\xed\xb0\x80", sourceIllegal);
	expect_error("\xed\xaf\xbf\xed\xbf\xbf", sourceIllegal);

	// test higher level conversions

	std::string utf8;
	std::copy(utf8_source.begin(), utf8_source.end(), std::back_inserter(utf8));

	std::wstring wide;
	utf8_conv_result_t ret = utf8_wchar(utf8, wide);
	TEST_EQUAL(ret, conversion_ok);

	std::string identity;
	ret = wchar_utf8(wide, identity);
	TEST_EQUAL(ret, conversion_ok);

	TEST_EQUAL(utf8, identity);
	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "OrbitClientData/TracepointData.h"

#include "OrbitBase/Logging.h"
#include "OrbitBase/ThreadConstants.h"

using orbit_client_protos::TracepointEventInfo;

void TracepointData::EmplaceTracepointEvent(uint64_t time, uint64_t tracepoint_hash,
                                            int32_t process_id, int32_t thread_id, int32_t cpu,
                                            bool is_same_pid_as_target) {
  absl::MutexLock lock(&mutex_);
  num_total_tracepoint_events_++;

  orbit_client_protos::TracepointEventInfo event;
  event.set_time(time);
  CHECK(HasTracepointKey(tracepoint_hash));
  event.set_tracepoint_info_key(tracepoint_hash);
  event.set_tid(thread_id);
  event.set_pid(process_id);
  event.set_cpu(cpu);

  int32_t insertion_thread_id =
      (is_same_pid_as_target) ? thread_id : orbit_base::kNotTargetProcessTid;

  auto [event_map_iterator, unused_inserted] =
      thread_id_to_time_to_tracepoint_.try_emplace(insertion_thread_id);
  auto [unused_iterator, event_inserted] =
      event_map_iterator->second.try_emplace(time, std::move(event));
  if (!event_inserted) {
    ERROR(
        "Tracepoint event was not inserted as there was already an event on this time and "
        "thread.");
  }
}

void TracepointData::ForEachTracepointEvent(
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) const {
  absl::MutexLock lock(&mutex_);
  for (auto const& entry : thread_id_to_time_to_tracepoint_) {
    for (auto const& time_to_tracepoint_event : entry.second) {
      action(time_to_tracepoint_event.second);
    }
  }
}

namespace {
void ForEachTracepointEventInRange(
    uint64_t min_tick, uint64_t max_tick_exclusive,
    const std::map<uint64_t, orbit_client_protos::TracepointEventInfo>& time_to_tracepoint_events,
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) {
  for (auto time_to_tracepoint_event = time_to_tracepoint_events.lower_bound(min_tick);
       time_to_tracepoint_event->first < max_tick_exclusive &&
       (time_to_tracepoint_event != time_to_tracepoint_events.end());
       ++time_to_tracepoint_event) {
    action(time_to_tracepoint_event->second);
  }
}
}  // namespace

void TracepointData::ForEachTracepointEventOfThreadInTimeRange(
    int32_t thread_id, uint64_t min_tick, uint64_t max_tick_exclusive,
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) const {
  absl::MutexLock lock(&mutex_);
  if (thread_id == orbit_base::kAllThreadsOfAllProcessesTid) {
    for (const auto& [unused_thread_id, time_to_tracepoint] : thread_id_to_time_to_tracepoint_) {
      ForEachTracepointEventInRange(min_tick, max_tick_exclusive, time_to_tracepoint, action);
    }
  } else if (thread_id == orbit_base::kAllProcessThreadsTid) {
    for (const auto& [thread_id, time_to_tracepoint] : thread_id_to_time_to_tracepoint_) {
      if (thread_id == orbit_base::kNotTargetProcessTid) {
        continue;
      }
      ForEachTracepointEventInRange(min_tick, max_tick_exclusive, time_to_tracepoint, action);
    }
  } else {
    const auto& it = thread_id_to_time_to_tracepoint_.find(thread_id);
    if (it == thread_id_to_time_to_tracepoint_.end()) {
      return;
    }
    ForEachTracepointEventInRange(min_tick, max_tick_exclusive, it->second, action);
  }
}

uint32_t TracepointData::GetNumTracepointEventsForThreadId(int32_t thread_id) const {
  absl::MutexLock lock(&mutex_);
  if (thread_id == orbit_base::kAllThreadsOfAllProcessesTid) {
    return num_total_tracepoint_events_;
  }
  if (thread_id == orbit_base::kAllProcessThreadsTid) {
    const auto not_target_process_tracepoints_it =
        thread_id_to_time_to_tracepoint_.find(orbit_base::kNotTargetProcessTid);
    if (not_target_process_tracepoints_it == thread_id_to_time_to_tracepoint_.end()) {
      return num_total_tracepoint_events_;
    }
    return num_total_tracepoint_events_ - not_target_process_tracepoints_it->second.size();
  }

  const auto& it = thread_id_to_time_to_tracepoint_.find(thread_id);
  if (it == thread_id_to_time_to_tracepoint_.end()) {
    return 0;
  }
  return it->second.size();
}

bool TracepointData::AddUniqueTracepointInfo(uint64_t key,
                                             orbit_grpc_protos::TracepointInfo tracepoint) {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  auto [unused_it, inserted] = unique_tracepoints_.try_emplace(key, std::move(tracepoint));
  return inserted;
}

orbit_grpc_protos::TracepointInfo TracepointData::GetTracepointInfo(uint64_t hash) const {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  auto it = unique_tracepoints_.find(hash);
  if (it != unique_tracepoints_.end()) {
    return it->second;
  }
  return {};
}

bool TracepointData::HasTracepointKey(uint64_t key) const {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  return unique_tracepoints_.contains(key);
}

void TracepointData::ForEachUniqueTracepointInfo(
    const std::function<void(const orbit_client_protos::TracepointInfo&)>& action) const {
  absl::MutexLock lock(&unique_tracepoints_mutex_);
  for (const auto& it : unique_tracepoints_) {
    orbit_client_protos::TracepointInfo tracepoint_info;
    tracepoint_info.set_category(it.second.category());
    tracepoint_info.set_name(it.second.name());
    tracepoint_info.set_tracepoint_info_key(it.first);
    action(tracepoint_info);
  }
}
<commit_msg>Fix bug in TracepointData.cpp<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "OrbitClientData/TracepointData.h"

#include "OrbitBase/Logging.h"
#include "OrbitBase/ThreadConstants.h"

using orbit_client_protos::TracepointEventInfo;

void TracepointData::EmplaceTracepointEvent(uint64_t time, uint64_t tracepoint_hash,
                                            int32_t process_id, int32_t thread_id, int32_t cpu,
                                            bool is_same_pid_as_target) {
  absl::MutexLock lock(&mutex_);
  num_total_tracepoint_events_++;

  orbit_client_protos::TracepointEventInfo event;
  event.set_time(time);
  CHECK(HasTracepointKey(tracepoint_hash));
  event.set_tracepoint_info_key(tracepoint_hash);
  event.set_tid(thread_id);
  event.set_pid(process_id);
  event.set_cpu(cpu);

  int32_t insertion_thread_id =
      (is_same_pid_as_target) ? thread_id : orbit_base::kNotTargetProcessTid;

  auto [event_map_iterator, unused_inserted] =
      thread_id_to_time_to_tracepoint_.try_emplace(insertion_thread_id);
  auto [unused_iterator, event_inserted] =
      event_map_iterator->second.try_emplace(time, std::move(event));
  if (!event_inserted) {
    ERROR(
        "Tracepoint event was not inserted as there was already an event on this time and "
        "thread.");
  }
}

void TracepointData::ForEachTracepointEvent(
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) const {
  absl::MutexLock lock(&mutex_);
  for (auto const& entry : thread_id_to_time_to_tracepoint_) {
    for (auto const& time_to_tracepoint_event : entry.second) {
      action(time_to_tracepoint_event.second);
    }
  }
}

namespace {
void ForEachTracepointEventInRange(
    uint64_t min_tick, uint64_t max_tick_exclusive,
    const std::map<uint64_t, orbit_client_protos::TracepointEventInfo>& time_to_tracepoint_events,
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) {
  for (auto time_to_tracepoint_event = time_to_tracepoint_events.lower_bound(min_tick);
       time_to_tracepoint_event != time_to_tracepoint_events.end() &&
       time_to_tracepoint_event->first < max_tick_exclusive;
       ++time_to_tracepoint_event) {
    action(time_to_tracepoint_event->second);
  }
}
}  // namespace

void TracepointData::ForEachTracepointEventOfThreadInTimeRange(
    int32_t thread_id, uint64_t min_tick, uint64_t max_tick_exclusive,
    const std::function<void(const orbit_client_protos::TracepointEventInfo&)>& action) const {
  absl::MutexLock lock(&mutex_);
  if (thread_id == orbit_base::kAllThreadsOfAllProcessesTid) {
    for (const auto& [unused_thread_id, time_to_tracepoint] : thread_id_to_time_to_tracepoint_) {
      ForEachTracepointEventInRange(min_tick, max_tick_exclusive, time_to_tracepoint, action);
    }
  } else if (thread_id == orbit_base::kAllProcessThreadsTid) {
    for (const auto& [thread_id, time_to_tracepoint] : thread_id_to_time_to_tracepoint_) {
      if (thread_id == orbit_base::kNotTargetProcessTid) {
        continue;
      }
      ForEachTracepointEventInRange(min_tick, max_tick_exclusive, time_to_tracepoint, action);
    }
  } else {
    const auto& it = thread_id_to_time_to_tracepoint_.find(thread_id);
    if (it == thread_id_to_time_to_tracepoint_.end()) {
      return;
    }
    ForEachTracepointEventInRange(min_tick, max_tick_exclusive, it->second, action);
  }
}

uint32_t TracepointData::GetNumTracepointEventsForThreadId(int32_t thread_id) const {
  absl::MutexLock lock(&mutex_);
  if (thread_id == orbit_base::kAllThreadsOfAllProcessesTid) {
    return num_total_tracepoint_events_;
  }
  if (thread_id == orbit_base::kAllProcessThreadsTid) {
    const auto not_target_process_tracepoints_it =
        thread_id_to_time_to_tracepoint_.find(orbit_base::kNotTargetProcessTid);
    if (not_target_process_tracepoints_it == thread_id_to_time_to_tracepoint_.end()) {
      return num_total_tracepoint_events_;
    }
    return num_total_tracepoint_events_ - not_target_process_tracepoints_it->second.size();
  }

  const auto& it = thread_id_to_time_to_tracepoint_.find(thread_id);
  if (it == thread_id_to_time_to_tracepoint_.end()) {
    return 0;
  }
  return it->second.size();
}

bool TracepointData::AddUniqueTracepointInfo(uint64_t key,
                                             orbit_grpc_protos::TracepointInfo tracepoint) {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  auto [unused_it, inserted] = unique_tracepoints_.try_emplace(key, std::move(tracepoint));
  return inserted;
}

orbit_grpc_protos::TracepointInfo TracepointData::GetTracepointInfo(uint64_t hash) const {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  auto it = unique_tracepoints_.find(hash);
  if (it != unique_tracepoints_.end()) {
    return it->second;
  }
  return {};
}

bool TracepointData::HasTracepointKey(uint64_t key) const {
  absl::MutexLock lock{&unique_tracepoints_mutex_};
  return unique_tracepoints_.contains(key);
}

void TracepointData::ForEachUniqueTracepointInfo(
    const std::function<void(const orbit_client_protos::TracepointInfo&)>& action) const {
  absl::MutexLock lock(&unique_tracepoints_mutex_);
  for (const auto& it : unique_tracepoints_) {
    orbit_client_protos::TracepointInfo tracepoint_info;
    tracepoint_info.set_category(it.second.category());
    tracepoint_info.set_name(it.second.name());
    tracepoint_info.set_tracepoint_info_key(it.first);
    action(tracepoint_info);
  }
}
<|endoftext|>


<commit_before>/**
*  Copyright (C) 2016 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program 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 Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "repo_maker_selection_tree.h"
#include "../../core/model/bson/repo_node_reference.h"
#include "../modeloptimizer/repo_optimizer_ifc.h"

using namespace repo::manipulator::modelutility;

const static std::string REPO_LABEL_VISIBILITY_STATE = "toggleState";
const static std::string REPO_VISIBILITY_STATE_SHOW = "visible";
const static std::string REPO_VISIBILITY_STATE_HIDDEN = "invisible";
const static std::string REPO_VISIBILITY_STATE_HALF_HIDDEN = "parentOfInvisible";

SelectionTreeMaker::SelectionTreeMaker(
	const repo::core::model::RepoScene *scene)
	: scene(scene)
{
}

repo::lib::PropertyTree SelectionTreeMaker::generatePTree(
	const repo::core::model::RepoNode            *currentNode,
	std::unordered_map < std::string, std::pair < std::string, std::string >> &idMaps,
	std::vector<std::pair<std::string, std::string>>        &sharedIDToUniqueID,
	repo::lib::PropertyTree                      &idToMeshesTree,
	const std::string                            &currentPath,
	bool                                         &hiddenOnDefault,
	std::vector<std::string>                     &hiddenNode,
	std::vector<std::string>                     &meshIds) const
{
	repo::lib::PropertyTree tree;
	if (currentNode)
	{

		std::string idString = currentNode->getUniqueID().toString();
		repoInfo << "Processing : " << idString << "[" << currentNode->getName() << "]";

		repo::lib::RepoUUID sharedID = currentNode->getSharedID();
		std::string childPath = currentPath.empty() ? idString : currentPath + "__" + idString;

		auto children = scene->getChildrenAsNodes(repo::core::model::RepoScene::GraphType::DEFAULT, sharedID);
		std::vector<repo::lib::PropertyTree> childrenTrees;

		std::vector<repo::core::model::RepoNode*> childrenTypes[2];
		std::vector<repo::lib::RepoUUID> metaIDs;
		for (const auto &child : children)
		{
			if (child->getTypeAsEnum() == repo::core::model::NodeType::METADATA)
			{
				metaIDs.push_back(child->getUniqueID());
			}
			else
			{
				//Ensure IFC Space (if any) are put into the tree first.
				if (child->getName().find(IFC_TYPE_SPACE_LABEL) != std::string::npos)
					childrenTypes[0].push_back(child);
				else
					childrenTypes[1].push_back(child);

			}

		}

		bool hasHiddenChildren = false;
		for (const auto &childrenSet : childrenTypes)
		{
			for (const auto &child : childrenSet)
			{
				if (child)
				{
					switch (child->getTypeAsEnum())
					{
					case repo::core::model::NodeType::MESH:
						meshIds.push_back(child->getUniqueID().toString());
					case repo::core::model::NodeType::TRANSFORMATION:
					case repo::core::model::NodeType::CAMERA:
					case repo::core::model::NodeType::REFERENCE:
					{
						bool hiddenChild = false;
						std::vector<std::string> childrenMeshes;
						repoInfo << "Recursing with kid: " << "[" << child->getName() << "] Kid of " << idString;
						childrenTrees.push_back(generatePTree(child, idMaps, sharedIDToUniqueID, idToMeshesTree, childPath, hiddenChild, hiddenNode, childrenMeshes));
						hasHiddenChildren = hasHiddenChildren || hiddenChild;
						meshIds.insert(meshIds.end(), childrenMeshes.begin(), childrenMeshes.end());
					}
					}
				}
				else
				{
					repoDebug << "Null pointer for child node at generatePTree, current path : " << currentPath;
					repoError << "Unexpected error at selection tree generation, the tree may not be complete.";
				}
			}
		}
		std::string name = currentNode->getName();
		if (repo::core::model::NodeType::REFERENCE == currentNode->getTypeAsEnum())
		{
			if (auto refNode = dynamic_cast<const repo::core::model::ReferenceNode*>(currentNode))
			{
				auto refDb = refNode->getDatabaseName();
				name = (scene->getDatabaseName() == refDb ? "" : (refDb + "/")) + refNode->getProjectName();
			}
		}

		tree.addToTree("account", scene->getDatabaseName());
		tree.addToTree("project", scene->getProjectName());
		tree.addToTree("type", currentNode->getType());
		if (!name.empty())
			tree.addToTree("name", name);
		tree.addToTree("path", childPath);
		tree.addToTree("_id", idString);
		tree.addToTree("shared_id", sharedID.toString());
		tree.addToTree("children", childrenTrees);
		if (metaIDs.size())
			tree.addToTree("meta", metaIDs);

		if (name.find(IFC_TYPE_SPACE_LABEL) != std::string::npos
			&& currentNode->getTypeAsEnum() == repo::core::model::NodeType::MESH)
		{
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_HIDDEN);
			hiddenOnDefault = true;
			hiddenNode.push_back(idString);
		}
		else if (hiddenOnDefault || hasHiddenChildren)
		{
			hiddenOnDefault = (hiddenOnDefault || hasHiddenChildren);
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_HALF_HIDDEN);
		}
		else
		{
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_SHOW);
		}

		idMaps[idString] = { name, childPath };
		sharedIDToUniqueID.push_back({ idString, sharedID.toString() });
		if (meshIds.size())
			idToMeshesTree.addToTree(idString, meshIds);
		else if (currentNode->getTypeAsEnum() == repo::core::model::NodeType::MESH){
			std::vector<repo::lib::RepoUUID> self = { currentNode->getUniqueID() };
			idToMeshesTree.addToTree(idString, self);
		}
	}
	else
	{
		repoDebug << "Null pointer at generatePTree, current path : " << currentPath;
		repoError << "Unexpected error at selection tree generation, the tree may not be complete.";
	}

	return tree;
}

std::map<std::string, std::vector<uint8_t>> SelectionTreeMaker::getSelectionTreeAsBuffer() const
{
	auto trees = getSelectionTreeAsPropertyTree();
	std::map<std::string, std::vector<uint8_t>> buffer;
	for (const auto &tree : trees)
	{
		std::stringstream ss;
		tree.second.write_json(ss);
		std::string jsonString = ss.str();
		if (!jsonString.empty())
		{
			size_t byteLength = jsonString.size() * sizeof(*jsonString.data());
			buffer[tree.first] = std::vector<uint8_t>();
			buffer[tree.first].resize(byteLength);
			memcpy(buffer[tree.first].data(), jsonString.data(), byteLength);
		}
		else
		{
			repoError << "Failed to write selection tree into the buffer: JSON string is empty.";
		}
	}

	return buffer;
}

std::map<std::string, repo::lib::PropertyTree>  SelectionTreeMaker::getSelectionTreeAsPropertyTree() const
{
	std::map<std::string, repo::lib::PropertyTree> trees;

	repo::core::model::RepoNode *root;
	if (scene && (root = scene->getRoot(repo::core::model::RepoScene::GraphType::DEFAULT)))
	{
		std::unordered_map< std::string, std::pair<std::string, std::string>> map;
		std::vector<std::string> hiddenNodes, childrenMeshes;
		bool dummy = false;
		repo::lib::PropertyTree tree, settingsTree, treePathTree, shareIDToUniqueIDMap, idToMeshes;
		std::vector<std::pair<std::string, std::string>>  sharedIDToUniqueID;
		tree.mergeSubTree("nodes", generatePTree(root, map, sharedIDToUniqueID, idToMeshes, "", dummy, hiddenNodes, childrenMeshes));
		for (const auto pair : map)
		{
			//if there's an entry in maps it must have an entry in paths
			tree.addToTree("idToName." + pair.first, pair.second.first);
			treePathTree.addToTree("idToPath." + pair.first, pair.second.second);
		}
		for (const auto pair : sharedIDToUniqueID)
		{
			shareIDToUniqueIDMap.addToTree("idMap." + pair.first, pair.second);
		}

		trees["fulltree.json"] = tree;
		trees["tree_path.json"] = treePathTree;
		trees["idMap.json"] = shareIDToUniqueIDMap;
		trees["idToMeshes.json"] = idToMeshes;

		if (hiddenNodes.size())
		{
			settingsTree.addToTree("hiddenNodes", hiddenNodes);
			trees["modelProperties.json"] = settingsTree;
		}
	}
	else
	{
		repoError << "Failed to generate selection tree: scene is empty or default scene is not loaded";
	}

	return trees;
}

SelectionTreeMaker::~SelectionTreeMaker()
{
}<commit_msg>ISSUE #223 remove debug<commit_after>/**
*  Copyright (C) 2016 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program 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 Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "repo_maker_selection_tree.h"
#include "../../core/model/bson/repo_node_reference.h"
#include "../modeloptimizer/repo_optimizer_ifc.h"

using namespace repo::manipulator::modelutility;

const static std::string REPO_LABEL_VISIBILITY_STATE = "toggleState";
const static std::string REPO_VISIBILITY_STATE_SHOW = "visible";
const static std::string REPO_VISIBILITY_STATE_HIDDEN = "invisible";
const static std::string REPO_VISIBILITY_STATE_HALF_HIDDEN = "parentOfInvisible";

SelectionTreeMaker::SelectionTreeMaker(
	const repo::core::model::RepoScene *scene)
	: scene(scene)
{
}

repo::lib::PropertyTree SelectionTreeMaker::generatePTree(
	const repo::core::model::RepoNode            *currentNode,
	std::unordered_map < std::string, std::pair < std::string, std::string >> &idMaps,
	std::vector<std::pair<std::string, std::string>>        &sharedIDToUniqueID,
	repo::lib::PropertyTree                      &idToMeshesTree,
	const std::string                            &currentPath,
	bool                                         &hiddenOnDefault,
	std::vector<std::string>                     &hiddenNode,
	std::vector<std::string>                     &meshIds) const
{
	repo::lib::PropertyTree tree;
	if (currentNode)
	{

		std::string idString = currentNode->getUniqueID().toString();

		repo::lib::RepoUUID sharedID = currentNode->getSharedID();
		std::string childPath = currentPath.empty() ? idString : currentPath + "__" + idString;

		auto children = scene->getChildrenAsNodes(repo::core::model::RepoScene::GraphType::DEFAULT, sharedID);
		std::vector<repo::lib::PropertyTree> childrenTrees;

		std::vector<repo::core::model::RepoNode*> childrenTypes[2];
		std::vector<repo::lib::RepoUUID> metaIDs;
		for (const auto &child : children)
		{
			if (child->getTypeAsEnum() == repo::core::model::NodeType::METADATA)
			{
				metaIDs.push_back(child->getUniqueID());
			}
			else
			{
				//Ensure IFC Space (if any) are put into the tree first.
				if (child->getName().find(IFC_TYPE_SPACE_LABEL) != std::string::npos)
					childrenTypes[0].push_back(child);
				else
					childrenTypes[1].push_back(child);

			}

		}

		bool hasHiddenChildren = false;
		for (const auto &childrenSet : childrenTypes)
		{
			for (const auto &child : childrenSet)
			{
				if (child)
				{
					switch (child->getTypeAsEnum())
					{
					case repo::core::model::NodeType::MESH:
						meshIds.push_back(child->getUniqueID().toString());
					case repo::core::model::NodeType::TRANSFORMATION:
					case repo::core::model::NodeType::CAMERA:
					case repo::core::model::NodeType::REFERENCE:
					{
						bool hiddenChild = false;
						std::vector<std::string> childrenMeshes;
						childrenTrees.push_back(generatePTree(child, idMaps, sharedIDToUniqueID, idToMeshesTree, childPath, hiddenChild, hiddenNode, childrenMeshes));
						hasHiddenChildren = hasHiddenChildren || hiddenChild;
						meshIds.insert(meshIds.end(), childrenMeshes.begin(), childrenMeshes.end());
					}
					}
				}
				else
				{
					repoDebug << "Null pointer for child node at generatePTree, current path : " << currentPath;
					repoError << "Unexpected error at selection tree generation, the tree may not be complete.";
				}
			}
		}
		std::string name = currentNode->getName();
		if (repo::core::model::NodeType::REFERENCE == currentNode->getTypeAsEnum())
		{
			if (auto refNode = dynamic_cast<const repo::core::model::ReferenceNode*>(currentNode))
			{
				auto refDb = refNode->getDatabaseName();
				name = (scene->getDatabaseName() == refDb ? "" : (refDb + "/")) + refNode->getProjectName();
			}
		}

		tree.addToTree("account", scene->getDatabaseName());
		tree.addToTree("project", scene->getProjectName());
		tree.addToTree("type", currentNode->getType());
		if (!name.empty())
			tree.addToTree("name", name);
		tree.addToTree("path", childPath);
		tree.addToTree("_id", idString);
		tree.addToTree("shared_id", sharedID.toString());
		tree.addToTree("children", childrenTrees);
		if (metaIDs.size())
			tree.addToTree("meta", metaIDs);

		if (name.find(IFC_TYPE_SPACE_LABEL) != std::string::npos
			&& currentNode->getTypeAsEnum() == repo::core::model::NodeType::MESH)
		{
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_HIDDEN);
			hiddenOnDefault = true;
			hiddenNode.push_back(idString);
		}
		else if (hiddenOnDefault || hasHiddenChildren)
		{
			hiddenOnDefault = (hiddenOnDefault || hasHiddenChildren);
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_HALF_HIDDEN);
		}
		else
		{
			tree.addToTree(REPO_LABEL_VISIBILITY_STATE, REPO_VISIBILITY_STATE_SHOW);
		}

		idMaps[idString] = { name, childPath };
		sharedIDToUniqueID.push_back({ idString, sharedID.toString() });
		if (meshIds.size())
			idToMeshesTree.addToTree(idString, meshIds);
		else if (currentNode->getTypeAsEnum() == repo::core::model::NodeType::MESH){
			std::vector<repo::lib::RepoUUID> self = { currentNode->getUniqueID() };
			idToMeshesTree.addToTree(idString, self);
		}
	}
	else
	{
		repoDebug << "Null pointer at generatePTree, current path : " << currentPath;
		repoError << "Unexpected error at selection tree generation, the tree may not be complete.";
	}

	return tree;
}

std::map<std::string, std::vector<uint8_t>> SelectionTreeMaker::getSelectionTreeAsBuffer() const
{
	auto trees = getSelectionTreeAsPropertyTree();
	std::map<std::string, std::vector<uint8_t>> buffer;
	for (const auto &tree : trees)
	{
		std::stringstream ss;
		tree.second.write_json(ss);
		std::string jsonString = ss.str();
		if (!jsonString.empty())
		{
			size_t byteLength = jsonString.size() * sizeof(*jsonString.data());
			buffer[tree.first] = std::vector<uint8_t>();
			buffer[tree.first].resize(byteLength);
			memcpy(buffer[tree.first].data(), jsonString.data(), byteLength);
		}
		else
		{
			repoError << "Failed to write selection tree into the buffer: JSON string is empty.";
		}
	}

	return buffer;
}

std::map<std::string, repo::lib::PropertyTree>  SelectionTreeMaker::getSelectionTreeAsPropertyTree() const
{
	std::map<std::string, repo::lib::PropertyTree> trees;

	repo::core::model::RepoNode *root;
	if (scene && (root = scene->getRoot(repo::core::model::RepoScene::GraphType::DEFAULT)))
	{
		std::unordered_map< std::string, std::pair<std::string, std::string>> map;
		std::vector<std::string> hiddenNodes, childrenMeshes;
		bool dummy = false;
		repo::lib::PropertyTree tree, settingsTree, treePathTree, shareIDToUniqueIDMap, idToMeshes;
		std::vector<std::pair<std::string, std::string>>  sharedIDToUniqueID;
		tree.mergeSubTree("nodes", generatePTree(root, map, sharedIDToUniqueID, idToMeshes, "", dummy, hiddenNodes, childrenMeshes));
		for (const auto pair : map)
		{
			//if there's an entry in maps it must have an entry in paths
			tree.addToTree("idToName." + pair.first, pair.second.first);
			treePathTree.addToTree("idToPath." + pair.first, pair.second.second);
		}
		for (const auto pair : sharedIDToUniqueID)
		{
			shareIDToUniqueIDMap.addToTree("idMap." + pair.first, pair.second);
		}

		trees["fulltree.json"] = tree;
		trees["tree_path.json"] = treePathTree;
		trees["idMap.json"] = shareIDToUniqueIDMap;
		trees["idToMeshes.json"] = idToMeshes;

		if (hiddenNodes.size())
		{
			settingsTree.addToTree("hiddenNodes", hiddenNodes);
			trees["modelProperties.json"] = settingsTree;
		}
	}
	else
	{
		repoError << "Failed to generate selection tree: scene is empty or default scene is not loaded";
	}

	return trees;
}

SelectionTreeMaker::~SelectionTreeMaker()
{
}<|endoftext|>


<commit_before>// spatial_type.cpp
//
#include "common/common.h"
#include "spatial_type.h"
#include "page_info.h"

namespace sdl { namespace db { namespace {

namespace hilbert { //FIXME: make static array to map (X,Y) <=> distance

//https://en.wikipedia.org/wiki/Hilbert_curve
// The following code performs the mappings in both directions,
// using iteration and bit operations rather than recursion.
// It assumes a square divided into n by n cells, for n a power of 2,
// with integer coordinates, with (0,0) in the lower left corner, (n-1,n-1) in the upper right corner,
// and a distance d that starts at 0 in the lower left corner and goes to n^2-1 in the lower-right corner.

//rotate/flip a quadrant appropriately
void rot(const int n, int & x, int & y, const int rx, const int ry) {
    SDL_ASSERT(is_power_two(n));
    if (ry == 0) {
        if (rx == 1) {
            x = n - 1 - x;
            y = n - 1 - y;
        }
        //Swap x and y
        auto t  = x;
        x = y;
        y = t;
    }
}

//convert (x,y) to d
int xy2d(const int n, int x, int y) {
    SDL_ASSERT(is_power_two(n));
    SDL_ASSERT(x < n);
    SDL_ASSERT(y < n);
    int rx, ry, d = 0;
    for (int s = n/2; s > 0; s /= 2) {
        rx = (x & s) > 0;
        ry = (y & s) > 0;
        d += s * s * ((3 * rx) ^ ry);
        rot(s, x, y, rx, ry);
    }
    SDL_ASSERT((d >= 0) && (d < (n * n)));
    SDL_ASSERT(d < 256); // to be compatible with spatial_cell::id_type
    return d;
}

//convert d to (x,y)
void d2xy(const int n, const int d, int & x, int & y) {
    SDL_ASSERT(is_power_two(n));
    SDL_ASSERT((d >= 0) && (d < (n * n)));
    int rx, ry, t = d;
    x = y = 0;
    for (int s = 1; s < n; s *= 2) {
        rx = 1 & (t / 2);
        ry = 1 & (t ^ rx);
        rot(s, x, y, rx, ry);
        x += s * rx;
        y += s * ry;
        t /= 4;
    }
    SDL_ASSERT((x >= 0) && (x < n));
    SDL_ASSERT((y >= 0) && (y < n));
}

} // hilbert

point_t<double> project_globe(spatial_point const & p)
{
    SDL_ASSERT(p.is_valid());
    point_t<double> p1, p2, p3;
    double meridian, sector;
    p3.X = 0.5;
    if (p.latitude < 0) { // south hemisphere
        p3.Y = 0.25;
        if (p.longitude >= 0) { // north-east
            if (p.longitude <= 45) {
                p1 = { 1, 0.25 };
                p2 = { 1, 0 };
                meridian = 0;
                sector = 45;
            }
            else if (p.longitude <= 135) {
                p1 = { 1, 0 };
                p2 = { 0, 0 };
                meridian = 45;
                sector = 90;
            }
            else {
                SDL_ASSERT(p.longitude <= 180);
                p1 = { 0, 0 };
                p2 = { 0, 0.25 };
                meridian = 135;
                sector = 45;
            }
        }
        else { // north-west
            if (p.longitude >= -45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 0.25 };
                meridian = -45;
                sector = 45;
            }
            else if (p.longitude >= -135) {
                p1 = { 0, 0.5 };
                p2 = { 1, 0.5 };
                meridian = -135;
                sector = 90;
            }
            else {
                SDL_ASSERT(-180 <= p.longitude);
                p1 = { 0, 0.25 };
                p2 = { 0, 0.5 };
                meridian = -180;
                sector = 45;
            }
        }
    }
    else { // north hemisphere
        p3.Y = 0.75;
        if (p.longitude >= 0) { // south-east
            if (p.longitude <= 45) {
                p1 = { 1, 0.75 };
                p2 = { 1, 1 };
                meridian = 0;
                sector = 45;
            }
            else if (p.longitude <= 135) {
                p1 = { 1, 1 };
                p2 = { 0, 1 };
                meridian = 45;
                sector = 90;
            }
            else {
                SDL_ASSERT(p.longitude <= 180);
                p1 = { 0, 1 };
                p2 = { 0, 0.75 };
                meridian = 135;
                sector = 45;
            }
        }
        else { // south-west
            if (p.longitude >= -45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 0.75 };
                meridian = -45;
                sector = 45;
            }
            else if (p.longitude >= -135) {
                p1 = { 0, 0.5 };
                p2 = { 1, 0.5 };
                meridian = -135;
                sector = 90;
            }
            else {
                SDL_ASSERT(-180 <= p.longitude);
                p1 = { 0, 0.75 };
                p2 = { 0, 0.5 };
                meridian = -180;
                sector = 45;
            }
        }
    }
    SDL_ASSERT(p.longitude >= meridian);
    SDL_ASSERT((p.longitude - meridian) <= sector);
    double const move_longitude = (p.longitude - meridian) / sector;
    SDL_ASSERT(move_longitude <= 1);
    const point_t<double> base = {
        p1.X + (p2.X - p1.X) * move_longitude,
        p1.Y + (p2.Y - p1.Y) * move_longitude
    };
    double const move_latitude = std::fabs(p.latitude) / 90.0;
    const point_t<double> result = {
        base.X + (p3.X - base.X) * move_latitude,
        base.Y + (p3.Y - base.Y) * move_latitude
    };
    SDL_ASSERT((result.X >= 0) && (result.Y >= 0));
    SDL_ASSERT((result.X <= 1) && (result.Y <= 1));
    return result;
}

} // namespace

point_t<int> spatial_transform::make_XY(spatial_cell const & p, spatial_grid::grid_size const grid)
{
    point_t<int> xy;
    hilbert::d2xy(grid, p[0], xy.X, xy.Y);
    return xy;
}

vector_cell spatial_transform::make_cell(spatial_point const & p, spatial_grid const & grid)
{
    const point_t<double> globe = project_globe(p);

    const int g_0 = grid[0];
    const int X = a_min<int>(static_cast<int>(globe.X * g_0), g_0 - 1);
    const int Y = a_min<int>(static_cast<int>(globe.Y * g_0), g_0 - 1);

    const int dist_0 = hilbert::xy2d(g_0, X, Y);

    vector_cell vc(1);
    vc[0][0] = static_cast<spatial_cell::id_type>(dist_0);
    vc[0].data.last = spatial_cell::last_4; //FIXME: to be tested
    return vc;
}

spatial_point spatial_transform::make_point(spatial_cell const & p, spatial_grid const & grid)
{
    const int g_0 = grid[0];
    const int g_1 = grid[1];
    const int g_2 = grid[2];
    const int g_3 = grid[3];
    return {};
}

} // db
} // sdl

#if SDL_DEBUG
namespace sdl {
    namespace db {
        namespace {
            class unit_test {
            public:
                unit_test()
                {
                    A_STATIC_ASSERT_IS_POD(spatial_cell);
                    A_STATIC_ASSERT_IS_POD(spatial_point);
                    A_STATIC_ASSERT_IS_POD(point_t<double>);

                    static_assert(sizeof(spatial_cell) == 5, "");
                    static_assert(sizeof(spatial_point) == 16, "");

                    static_assert(is_power_2<1>::value, "");
                    static_assert(is_power_2<spatial_grid::LOW>::value, "");
                    static_assert(is_power_2<spatial_grid::MEDIUM>::value, "");
                    static_assert(is_power_2<spatial_grid::HIGH>::value, "");

                    SDL_ASSERT(is_power_two(spatial_grid::LOW));
                    SDL_ASSERT(is_power_two(spatial_grid::MEDIUM));
                    SDL_ASSERT(is_power_two(spatial_grid::HIGH));

                    {
                        spatial_cell x{};
                        spatial_cell y{};
                        SDL_ASSERT(!(x < y));
                    }
                    test_hilbert();
                    test_spatial();
                }
            private:
                static void trace_hilbert(const int n) {
                    for (int y = 0; y < n; ++y) {
                        std::cout << y;
                        for (int x = 0; x < n; ++x) {
                            const int d = hilbert::xy2d(n, x, y);
                            std::cout << "," << d;
                        }
                        std::cout << std::endl;
                    }
                }
                static void test_hilbert(const int n) {
                    for (int d = 0; d < (n * n); ++d) {
                        int x = 0, y = 0;
                        hilbert::d2xy(n, d, x, y);
                        SDL_ASSERT(d == hilbert::xy2d(n, x, y));
                        //SDL_TRACE("d2xy: n = ", n, " d = ", d, " x = ", x, " y = ", y);
                    }
                }
                static void test_hilbert() {
                    spatial_grid::grid_size const sz = spatial_grid::HIGH;
                    for (int i = 0; (1 << i) <= sz; ++i) {
                        test_hilbert(1 << i);
                    }
                }
                static void trace_cell(const vector_cell & vc) {
                    SDL_ASSERT(!vc.empty());
                    for (auto & v : vc) {
                        SDL_TRACE(to_string::type(v));
                    }
                }
                static void test_spatial(const spatial_grid & grid) {
                    if (0) {
                        spatial_point p1{}, p2{};
                        for (int i = 0; i <= 4; ++i) {
                        for (int j = 0; j <= 2; ++j) {
                            p1.longitude = 45 * i;
                            p2.longitude = -45 * i;
                            p1.latitude = 45 * j;
                            p2.latitude = -45 * j;
                            project_globe(p1);
                            project_globe(p2);
                            spatial_transform::make_cell(p1, spatial_grid(spatial_grid::HIGH));
                        }}
                    }
                    if (0) {
                        static const spatial_point test[] = { // latitude, longitude
                            { 0, 0 },
                            { 0, 135 },
                            { 0, 90 },
                            { 90, 0 },
                            { -90, 0 },
                            { 0, -45 },
                            { 45, 45 },
                            { 0, 180 },
                            { 0, -180 },
                            { 0, 131 },
                            { 0, 134 },
                            { 0, 144 },
                            { 0, 145 },
                            { 0, 166 },
                            { 0, -86 },             // cell_id = 128-234-255-15-4
                            { 55.7975, 49.2194 },   // cell_id = 157-178-149-55-4
                            { 47.2629, 39.7111 },   // cell_id = 163-78-72-221-4
                            { 47.261, 39.7068 },    // cell_id = 163-78-72-223-4
                            { 55.7831, 37.3567 },   // cell_id = 156-38-25-118-4
                        };
                        for (size_t i = 0; i < A_ARRAY_SIZE(test); ++i) {
                            std::cout << i << ": " << to_string::type(test[i]) << " => ";
                            trace_cell(spatial_transform::make_cell(test[i], grid));
                        }
                        SDL_TRACE();
                    }
                }
                static void test_spatial() {
                    test_spatial(spatial_grid(spatial_grid::HIGH));
                }
            };
            static unit_test s_test;
        }
    } // db
} // sdl
#endif //#if SV_DEBUG
<commit_msg>todo: project_globe<commit_after>// spatial_type.cpp
//
#include "common/common.h"
#include "spatial_type.h"
#include "page_info.h"

namespace sdl { namespace db { namespace {

namespace hilbert { //FIXME: make static array to map (X,Y) <=> distance

//https://en.wikipedia.org/wiki/Hilbert_curve
// The following code performs the mappings in both directions,
// using iteration and bit operations rather than recursion.
// It assumes a square divided into n by n cells, for n a power of 2,
// with integer coordinates, with (0,0) in the lower left corner, (n-1,n-1) in the upper right corner,
// and a distance d that starts at 0 in the lower left corner and goes to n^2-1 in the lower-right corner.

//rotate/flip a quadrant appropriately
void rot(const int n, int & x, int & y, const int rx, const int ry) {
    SDL_ASSERT(is_power_two(n));
    if (ry == 0) {
        if (rx == 1) {
            x = n - 1 - x;
            y = n - 1 - y;
        }
        //Swap x and y
        auto t  = x;
        x = y;
        y = t;
    }
}

//convert (x,y) to d
int xy2d(const int n, int x, int y) {
    SDL_ASSERT(is_power_two(n));
    SDL_ASSERT(x < n);
    SDL_ASSERT(y < n);
    int rx, ry, d = 0;
    for (int s = n/2; s > 0; s /= 2) {
        rx = (x & s) > 0;
        ry = (y & s) > 0;
        d += s * s * ((3 * rx) ^ ry);
        rot(s, x, y, rx, ry);
    }
    SDL_ASSERT((d >= 0) && (d < (n * n)));
    SDL_ASSERT(d < 256); // to be compatible with spatial_cell::id_type
    return d;
}

//convert d to (x,y)
void d2xy(const int n, const int d, int & x, int & y) {
    SDL_ASSERT(is_power_two(n));
    SDL_ASSERT((d >= 0) && (d < (n * n)));
    int rx, ry, t = d;
    x = y = 0;
    for (int s = 1; s < n; s *= 2) {
        rx = 1 & (t / 2);
        ry = 1 & (t ^ rx);
        rot(s, x, y, rx, ry);
        x += s * rx;
        y += s * ry;
        t /= 4;
    }
    SDL_ASSERT((x >= 0) && (x < n));
    SDL_ASSERT((y >= 0) && (y < n));
}

} // hilbert

double longitude_distance(double const left, double const right)
{
    SDL_ASSERT(std::fabs(left) <= 180);
    SDL_ASSERT(std::fabs(right) <= 180);
    if (left >= 0) {
        if (right >= 0) {
            SDL_ASSERT(right >= left);
            return right - left;
        }
        return (right + 180) + (180 - left);
    }
    else {
        if (right < 0) {
            SDL_ASSERT(right >= left);
            return right - left;
        }
        return right - left;
    }
}

point_t<double> project_globe(spatial_point const & s)
{
    SDL_ASSERT(s.is_valid());

    const bool north_hemisphere = (s.latitude >= 0);
    const bool east_hemisphere = (s.longitude >= 0);

    point_t<double> p1, p2, p3;
    spatial_point s1, s2, s3;

    s1.latitude = s2.latitude = 0;
    s3.latitude = north_hemisphere ? 90 : -90;

    if (north_hemisphere) {
        p3 = { 0.5, 0.75 };
        if (east_hemisphere) {
            if (s.longitude <= 45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 1 };
                s1.longitude = -45;
                s2.longitude = 45;
                s3.longitude = 0;
            }
            else if (s.longitude <= 135) {
                p1 = { 1, 1 };
                p2 = { 0, 1 };
                s1.longitude = 45;
                s2.longitude = 135;
                s3.longitude = 90;
            }
            else {
                SDL_ASSERT(s.longitude <= 180);
                p1 = { 0, 1 };
                p2 = { 0, 0.5 };
                s1.longitude = 135;
                s2.longitude = -135;
                s3.longitude = 180;
            }
        }
        else { // west hemisphere
            SDL_ASSERT(s.longitude < 0);
            if (s.longitude >= -45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 1 };
                s1.longitude = -45;
                s2.longitude = 45;
                s3.longitude = 0;
            }
            else if (s.longitude >= -135) {
                p1 = { 0, 0.5 };
                p2 = { 1, 0.5 };
                s1.longitude = -135;
                s2.longitude = -45;
                s3.longitude = -90;
            }
            else {
                SDL_ASSERT(s.longitude >= -180);
                p1 = { 0, 1 };
                p2 = { 0, 0.5 };
                s1.longitude = 135;
                s2.longitude = -135;
                s3.longitude = -180;
            }
        }
        SDL_ASSERT(p1.Y >= 0.5);
        SDL_ASSERT(p2.Y >= 0.5);
    }
    else { // south hemisphere
        SDL_ASSERT(s.latitude < 0);
        p3 = { 0.5, 0.25 };
        if (east_hemisphere) {
            if (s.longitude <= 45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 0 };
                s1.longitude = -45;
                s2.longitude = 45;
                s3.longitude = 0;
            }
            else if (s.longitude <= 135) {
                p1 = { 1, 0 };
                p2 = { 0, 0 };
                s1.longitude = 45;
                s2.longitude = 135;
                s3.longitude = 90;
            }
            else {
                SDL_ASSERT(s.longitude <= 180);
                p1 = { 0, 0 };
                p2 = { 0, 0.5 };
                s1.longitude = 135;
                s2.longitude = -135;
                s3.longitude = 180;
            }
        }
        else { // west hemisphere
            SDL_ASSERT(s.longitude < 0);
            if (s.longitude >= -45) {
                p1 = { 1, 0.5 };
                p2 = { 1, 0 };
                s1.longitude = -45;
                s2.longitude = 45;
                s3.longitude = 0;
            }
            else if (s.longitude >= -135) {
                p1 = { 0, 0.5 };
                p2 = { 1, 0.5 };
                s1.longitude = -135;
                s2.longitude = -45;
                s3.longitude = -90;
            }
            else {
                SDL_ASSERT(s.longitude >= -180);
                p1 = { 0, 0 };
                p2 = { 0, 0.5 };
                s1.longitude = 135;
                s2.longitude = -135;
                s3.longitude = -180;
            }
        }
        SDL_ASSERT(p1.Y <= 0.5);
        SDL_ASSERT(p2.Y <= 0.5);
    }
    SDL_ASSERT(!east_hemisphere || (s3.longitude >= 0));
    SDL_ASSERT(east_hemisphere || (s3.longitude <= 0));
    SDL_ASSERT(fequal(longitude_distance(s1.longitude, s2.longitude), 90.0));
    SDL_ASSERT(std::fabs(s.latitude - s3.latitude) <= 90);

    //https://en.wikipedia.org/wiki/Barycentric_coordinate_system

    return{};
}

} // namespace

point_t<int> spatial_transform::make_XY(spatial_cell const & p, spatial_grid::grid_size const grid)
{
    point_t<int> xy;
    hilbert::d2xy(grid, p[0], xy.X, xy.Y);
    return xy;
}

vector_cell spatial_transform::make_cell(spatial_point const & p, spatial_grid const & grid)
{
    const point_t<double> globe = project_globe(p);

    const int g_0 = grid[0];

    const point_t<double> d = {
        globe.X * g_0,
        globe.Y * g_0
    };
    const int X = a_min<int>(static_cast<int>(d.X), g_0 - 1);
    const int Y = a_min<int>(static_cast<int>(d.Y), g_0 - 1);

    const int dist_0 = hilbert::xy2d(g_0, X, Y);

    vector_cell vc(1);
    vc[0][0] = static_cast<spatial_cell::id_type>(dist_0);
    vc[0].data.last = spatial_cell::last_4; //FIXME: to be tested
    return vc;
}

spatial_point spatial_transform::make_point(spatial_cell const & p, spatial_grid const & grid)
{
    const int g_0 = grid[0];
    const int g_1 = grid[1];
    const int g_2 = grid[2];
    const int g_3 = grid[3];
    return {};
}

} // db
} // sdl

#if SDL_DEBUG
namespace sdl {
    namespace db {
        namespace {
            class unit_test {
            public:
                unit_test()
                {
                    A_STATIC_ASSERT_IS_POD(spatial_cell);
                    A_STATIC_ASSERT_IS_POD(spatial_point);
                    A_STATIC_ASSERT_IS_POD(point_t<double>);

                    static_assert(sizeof(spatial_cell) == 5, "");
                    static_assert(sizeof(spatial_point) == 16, "");

                    static_assert(is_power_2<1>::value, "");
                    static_assert(is_power_2<spatial_grid::LOW>::value, "");
                    static_assert(is_power_2<spatial_grid::MEDIUM>::value, "");
                    static_assert(is_power_2<spatial_grid::HIGH>::value, "");

                    SDL_ASSERT(is_power_two(spatial_grid::LOW));
                    SDL_ASSERT(is_power_two(spatial_grid::MEDIUM));
                    SDL_ASSERT(is_power_two(spatial_grid::HIGH));

                    {
                        spatial_cell x{};
                        spatial_cell y{};
                        SDL_ASSERT(!(x < y));
                    }
                    test_hilbert();
                    test_spatial();
                }
            private:
                static void trace_hilbert(const int n) {
                    for (int y = 0; y < n; ++y) {
                        std::cout << y;
                        for (int x = 0; x < n; ++x) {
                            const int d = hilbert::xy2d(n, x, y);
                            std::cout << "," << d;
                        }
                        std::cout << std::endl;
                    }
                }
                static void test_hilbert(const int n) {
                    for (int d = 0; d < (n * n); ++d) {
                        int x = 0, y = 0;
                        hilbert::d2xy(n, d, x, y);
                        SDL_ASSERT(d == hilbert::xy2d(n, x, y));
                        //SDL_TRACE("d2xy: n = ", n, " d = ", d, " x = ", x, " y = ", y);
                    }
                }
                static void test_hilbert() {
                    spatial_grid::grid_size const sz = spatial_grid::HIGH;
                    for (int i = 0; (1 << i) <= sz; ++i) {
                        test_hilbert(1 << i);
                    }
                }
                static void trace_cell(const vector_cell & vc) {
                    //SDL_ASSERT(!vc.empty());
                    for (auto & v : vc) {
                        SDL_TRACE(to_string::type(v));
                    }
                }
                static void test_spatial(const spatial_grid & grid) {
                    if (1) {
                        spatial_point p1{}, p2{};
                        for (int i = 0; i <= 4; ++i) {
                        for (int j = 0; j <= 2; ++j) {
                            p1.longitude = 45 * i;
                            p2.longitude = -45 * i;
                            p1.latitude = 45 * j;
                            p2.latitude = -45 * j;
                            project_globe(p1);
                            project_globe(p2);
                            spatial_transform::make_cell(p1, spatial_grid(spatial_grid::LOW));
                            spatial_transform::make_cell(p1, spatial_grid(spatial_grid::MEDIUM));
                            spatial_transform::make_cell(p1, spatial_grid(spatial_grid::HIGH));
                        }}
                    }
                    if (1) {
                        static const spatial_point test[] = { // latitude, longitude
                            { 0, 0 },
                            { 0, 135 },
                            { 0, 90 },
                            { 90, 0 },
                            { -90, 0 },
                            { 0, -45 },
                            { 45, 45 },
                            { 0, 180 },
                            { 0, -180 },
                            { 0, 131 },
                            { 0, 134 },
                            { 0, 144 },
                            { 0, 145 },
                            { 0, 166 },
                            { 48.7139, 44.4984 },   // cell_id = 156-163-67-177-4
                            { 55.7975, 49.2194 },   // cell_id = 157-178-149-55-4
                            { 47.2629, 39.7111 },   // cell_id = 163-78-72-221-4
                            { 47.261, 39.7068 },    // cell_id = 163-78-72-223-4
                            { 55.7831, 37.3567 },   // cell_id = 156-38-25-118-4
                            { 0, -86 },             // cell_id = 128-234-255-15-4
                            { 45, -135 },           // cell_id = 70-170-170-170-4
                            { 45, 135 },            // cell_id = 91-255-255-255-4
                            { 45, 0 },              // cell_id = 160-236-255-239-4 | 181-153-170-154-4
                            { 45, -45 },            // cell_id = 134-170-170-170-4 | 137-255-255-255-4 | 182-0-0-0-4 | 185-85-85-85-4
                        };
                        for (size_t i = 0; i < A_ARRAY_SIZE(test); ++i) {
                            std::cout << i << ": " << to_string::type(test[i]) << " => ";
                            trace_cell(spatial_transform::make_cell(test[i], grid));
                        }
                        SDL_TRACE();
                    }
                }
                static void test_spatial() {
                    test_spatial(spatial_grid(spatial_grid::HIGH));
                }
            };
            static unit_test s_test;
        }
    } // db
} // sdl
#endif //#if SV_DEBUG

<|endoftext|>


<commit_before>#include "rltk.hpp"
#include "texture.hpp"
#include <memory>

namespace rltk {

std::unique_ptr<sf::RenderWindow> main_window;
std::unique_ptr<virtual_terminal> root_console;

sf::RenderWindow * get_window() {
	return main_window.get();
}

virtual_terminal * get_root_console() {
    return root_console.get();
}

void init(const int window_width, const int window_height, const std::string window_title) {
	main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(window_width, window_height, sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close), window_title);
    main_window->setVerticalSyncEnabled(true);
}

void run(std::function<void(double)> on_tick, const std::string root_console_font) {
    root_console = std::make_unique<virtual_terminal>(root_console_font, 0, 0);
    sf::Vector2u size_pixels = main_window->getSize();
    root_console->resize_pixels(size_pixels.x, size_pixels.y);

    double duration_ms = 0.0;
    while (main_window->isOpen())
    {
    	clock_t start_time = clock();

        sf::Event event;
        while (main_window->pollEvent(event))
        {
            if (event.type == sf::Event::Closed) {
                main_window->close();
            }
        }

        main_window->clear();
        root_console->clear();

        on_tick(duration_ms);

        root_console->render(*main_window);

        main_window->display();

        duration_ms = ((clock() - start_time) * 1000.0) / CLOCKS_PER_SEC;
    }
}

}
<commit_msg>Support window resize.<commit_after>#include "rltk.hpp"
#include "texture.hpp"
#include <memory>

namespace rltk {

std::unique_ptr<sf::RenderWindow> main_window;
std::unique_ptr<virtual_terminal> root_console;

sf::RenderWindow * get_window() {
	return main_window.get();
}

virtual_terminal * get_root_console() {
    return root_console.get();
}

void init(const int window_width, const int window_height, const std::string window_title) {
	main_window = std::make_unique<sf::RenderWindow>(sf::VideoMode(window_width, window_height, sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close), window_title);
    main_window->setVerticalSyncEnabled(true);
}

void run(std::function<void(double)> on_tick, const std::string root_console_font) {
    root_console = std::make_unique<virtual_terminal>(root_console_font, 0, 0);
    sf::Vector2u size_pixels = main_window->getSize();
    root_console->resize_pixels(size_pixels.x, size_pixels.y);

    double duration_ms = 0.0;
    while (main_window->isOpen())
    {
    	clock_t start_time = clock();

        sf::Event event;
        while (main_window->pollEvent(event))
        {
            if (event.type == sf::Event::Closed) {
                main_window->close();
            } else if (event.type == sf::Event::Resized) {
                sf::Vector2u size_pixels = main_window->getSize();
                root_console->resize_pixels(event.size.width, event.size.height);
                main_window->setView(sf::View(sf::FloatRect(0.f, 0.f, event.size.width, event.size.height)));
            }

        }

        main_window->clear();
        root_console->clear();

        on_tick(duration_ms);

        root_console->render(*main_window);

        main_window->display();

        duration_ms = ((clock() - start_time) * 1000.0) / CLOCKS_PER_SEC;
    }
}

}
<|endoftext|>