<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "OffscreenCanvas.h"
#include "Player.h"

#include "../graphics/FBO.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

VideoWriter::VideoWriter(CanvasPtr pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bHasValidData(false),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bPaused(false),
      m_PauseTime(0),
      m_bStopped(false),
      m_CurFrame(0),
      m_StartTime(-1),
      m_bFramePending(false)
{
    m_FrameSize = m_pCanvas->getSize();
#ifdef WIN32
    int fd = _open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);

#else
    int fd = open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU);
#endif
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
#ifdef WIN32
    _close(fd);
#else
    close(fd);
#endif
    remove(m_sOutFileName.c_str());
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, m_FrameSize, m_FrameRate,
            qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
    CanvasPtr pMainCanvas = Player::get()->getMainCanvas();
    if (pMainCanvas != m_pCanvas) {
        m_pFBO = dynamic_pointer_cast<OffscreenCanvas>(m_pCanvas)->getFBO();
        m_pCanvas->registerPreRenderListener(this);
    }
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
        if (m_pFBO) {
            m_pCanvas->unregisterPreRenderListener(this);
        }
    }
}

void VideoWriter::pause()
{
    if (m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when paused.");
    }
    if (m_bStopped) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when stopped.");
    }
    m_bPaused = true;
    m_PauseStartTime = Player::get()->getFrameTime();
}

void VideoWriter::play()
{
    if (!m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "VideoWriter::play() called when not paused.");
    }
    m_bPaused = false;
    m_PauseTime += (Player::get()->getFrameTime() - m_PauseStartTime);
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    // The VideoWriter handles OffscreenCanvas and MainCanvas differently:
    // For MainCanvas, it simply does a screenshot onFrameEnd and sends that to the
    // VideoWriterThread immediately.
    // For OffscreenCanvas, an asynchronous PBO readback is started in onFrameEnd.
    // In the next frame's onPreRender, the data is read into a bitmap and sent to
    // the VideoWriterThread.
    if (m_StartTime == -1) {
        m_StartTime = Player::get()->getFrameTime();
    }
    if (!m_bPaused) {
        if (m_bSyncToPlayback) {
            readFrameFromFBO();
        } else {
            handleAutoSynchronizedFrame();
        }
    }

    if (!m_pFBO) {
        getFrameFromPBO();
    }
}

void VideoWriter::onPreRender()
{
    getFrameFromPBO();
}

void VideoWriter::readFrameFromFBO()
{
    if (m_pFBO) {
        m_pFBO->moveToPBO(0);
        m_bFramePending = true;
    } else {
        BitmapPtr pBmp = m_pCanvas->screenshot();
        sendFrame(pBmp);
    }
}

void VideoWriter::getFrameFromPBO()
{
    if (m_bFramePending) {
        BitmapPtr pBmp = m_pFBO->getImageFromPBO();
        sendFrame(pBmp);
        m_bFramePending = false;
    }
}

void VideoWriter::sendFrame(BitmapPtr pBitmap)
{
    m_CurFrame++;
    m_bHasValidData = true;
    m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
}

void VideoWriter::handleAutoSynchronizedFrame()
{
    long long movieTime = Player::get()->getFrameTime() - m_StartTime - m_PauseTime;
    double timePerFrame = 1000./m_FrameRate;
    int wantedFrame = int(movieTime/timePerFrame+0.1);
    if (wantedFrame > m_CurFrame) {
        readFrameFromFBO();
        m_CurFrame = wantedFrame;
    }
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    sendFrame(pBmp);
}

}
<commit_msg>Fixed VideoWriter framerate issue.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "OffscreenCanvas.h"
#include "Player.h"

#include "../graphics/FBO.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

VideoWriter::VideoWriter(CanvasPtr pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bHasValidData(false),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bPaused(false),
      m_PauseTime(0),
      m_bStopped(false),
      m_CurFrame(0),
      m_StartTime(-1),
      m_bFramePending(false)
{
    m_FrameSize = m_pCanvas->getSize();
#ifdef WIN32
    int fd = _open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);

#else
    int fd = open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU);
#endif
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
#ifdef WIN32
    _close(fd);
#else
    close(fd);
#endif
    remove(m_sOutFileName.c_str());
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, m_FrameSize, m_FrameRate,
            qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
    CanvasPtr pMainCanvas = Player::get()->getMainCanvas();
    if (pMainCanvas != m_pCanvas) {
        m_pFBO = dynamic_pointer_cast<OffscreenCanvas>(m_pCanvas)->getFBO();
        m_pCanvas->registerPreRenderListener(this);
    }
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
        if (m_pFBO) {
            m_pCanvas->unregisterPreRenderListener(this);
        }
    }
}

void VideoWriter::pause()
{
    if (m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when paused.");
    }
    if (m_bStopped) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when stopped.");
    }
    m_bPaused = true;
    m_PauseStartTime = Player::get()->getFrameTime();
}

void VideoWriter::play()
{
    if (!m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "VideoWriter::play() called when not paused.");
    }
    m_bPaused = false;
    m_PauseTime += (Player::get()->getFrameTime() - m_PauseStartTime);
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    // The VideoWriter handles OffscreenCanvas and MainCanvas differently:
    // For MainCanvas, it simply does a screenshot onFrameEnd and sends that to the
    // VideoWriterThread immediately.
    // For OffscreenCanvas, an asynchronous PBO readback is started in onFrameEnd.
    // In the next frame's onPreRender, the data is read into a bitmap and sent to
    // the VideoWriterThread.
    if (m_StartTime == -1) {
        m_StartTime = Player::get()->getFrameTime();
    }
    if (!m_bPaused) {
        if (m_bSyncToPlayback) {
            readFrameFromFBO();
        } else {
            handleAutoSynchronizedFrame();
        }
    }

    if (!m_pFBO) {
        getFrameFromPBO();
    }
}

void VideoWriter::onPreRender()
{
    getFrameFromPBO();
}

void VideoWriter::readFrameFromFBO()
{
    if (m_pFBO) {
        m_pFBO->moveToPBO(0);
        m_bFramePending = true;
    } else {
        BitmapPtr pBmp = m_pCanvas->screenshot();
        sendFrame(pBmp);
    }
}

void VideoWriter::getFrameFromPBO()
{
    if (m_bFramePending) {
        BitmapPtr pBmp = m_pFBO->getImageFromPBO();
        sendFrame(pBmp);
        m_bFramePending = false;
    }
}

void VideoWriter::sendFrame(BitmapPtr pBitmap)
{
    m_CurFrame++;
    m_bHasValidData = true;
    m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
}

void VideoWriter::handleAutoSynchronizedFrame()
{
    long long movieTime = Player::get()->getFrameTime() - m_StartTime - m_PauseTime;
    double timePerFrame = 1000./m_FrameRate;
    int wantedFrame = int(movieTime/timePerFrame+0.1);
    if (wantedFrame > m_CurFrame) {
        readFrameFromFBO();
        if (wantedFrame > m_CurFrame + 1) {
            m_CurFrame = wantedFrame - 1;
        }
    }
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    sendFrame(pBmp);
}

}
<|endoftext|>


<commit_before>#include "logging.h"
#include "postProcessManager.h"
#include "shaderManager.h"
#include "resources.h"
#include "graphics/opengl.h"
#include <stddef.h>

PostProcessor::PostProcessor(string shadername, RenderChain* chain)
: shader(ShaderManager::getShader(shadername)), render_texture({128, 128}), chain(chain), enabled{false}
{
}

void PostProcessor::render(sp::RenderTarget& target)
{
    if (!enabled || true) // post processors disabled until all issues with RenderTexture has been solved.
    {
        chain->render(target);
        return;
    }
    target.finish();

    render_texture.setSize(target.getPhysicalSize());
    if (!render_texture.activateRenderTarget())
    {
        chain->render(target);
        return;
    }

    chain->render(target);
    target.finish();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    shader->bind();

    glUniform1i(shader->getUniformLocation("u_texture"), 0);
    glActiveTexture(GL_TEXTURE0);
    render_texture.bind();
    for(auto it : uniforms)
        glUniform1f(shader->getUniformLocation(it.first.c_str()), it.second);

    using VertexType = std::pair<glm::vec2, glm::vec2>;

    if (vertices_vbo == 0)
    {
        glGenBuffers(1, &vertices_vbo);
        glGenBuffers(1, &indices_vbo);

        std::vector<VertexType> vertex_data{
            {{-1, -1}, {0, 0}},
            {{-1,  1}, {0, 1}},
            {{ 1, -1}, {1, 0}},
            {{ 1,  1}, {1, 1}},
        };
        std::vector<uint16_t> index_data{0, 1, 2, 1, 3, 2};

        glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(VertexType) * vertex_data.size(), vertex_data.data(), GL_DYNAMIC_DRAW);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t) * index_data.size(), index_data.data(), GL_DYNAMIC_DRAW);
    }
    else
    {
        glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
    }

    glVertexAttribPointer(shader->getAttributeLocation("a_position"), 2, GL_FLOAT, GL_FALSE, static_cast<GLsizei>(sizeof(VertexType)), (void*)offsetof(VertexType, first));
    glEnableVertexAttribArray(shader->getAttributeLocation("a_position"));
    glVertexAttribPointer(shader->getAttributeLocation("a_texcoords"), 2, GL_FLOAT, GL_FALSE, static_cast<GLsizei>(sizeof(VertexType)), (void*)offsetof(VertexType, second));
    glEnableVertexAttribArray(shader->getAttributeLocation("a_texcoords"));

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);

    glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_NONE);
}

void PostProcessor::setUniform(string name, float value)
{
    uniforms[name] = value;
}

bool PostProcessor::onPointerMove(glm::vec2 position, sp::io::Pointer::ID id)
{
    return chain->onPointerMove(position, id);
}

void PostProcessor::onPointerLeave(sp::io::Pointer::ID id)
{
    chain->onPointerLeave(id);
}

bool PostProcessor::onPointerDown(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id)
{
    return chain->onPointerDown(button, position, id);
}

void PostProcessor::onPointerDrag(glm::vec2 position, sp::io::Pointer::ID id)
{
    chain->onPointerDrag(position, id);
}

void PostProcessor::onPointerUp(glm::vec2 position, sp::io::Pointer::ID id)
{
    chain->onPointerUp(position, id);
}

void PostProcessor::onTextInput(const string& text)
{
    chain->onTextInput(text);
}

void PostProcessor::onTextInput(sp::TextInputEvent e)
{
    chain->onTextInput(e);
}
<commit_msg>Enable post processor for a prerelease<commit_after>#include "logging.h"
#include "postProcessManager.h"
#include "shaderManager.h"
#include "resources.h"
#include "graphics/opengl.h"
#include <stddef.h>

PostProcessor::PostProcessor(string shadername, RenderChain* chain)
: shader(ShaderManager::getShader(shadername)), render_texture({128, 128}), chain(chain), enabled{false}
{
}

void PostProcessor::render(sp::RenderTarget& target)
{
    if (!enabled) // post processors disabled until all issues with RenderTexture has been solved.
    {
        chain->render(target);
        return;
    }
    target.finish();

    render_texture.setSize(target.getPhysicalSize());
    if (!render_texture.activateRenderTarget())
    {
        chain->render(target);
        return;
    }

    chain->render(target);
    target.finish();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    shader->bind();

    glUniform1i(shader->getUniformLocation("u_texture"), 0);
    glActiveTexture(GL_TEXTURE0);
    render_texture.bind();
    for(auto it : uniforms)
        glUniform1f(shader->getUniformLocation(it.first.c_str()), it.second);

    using VertexType = std::pair<glm::vec2, glm::vec2>;

    if (vertices_vbo == 0)
    {
        glGenBuffers(1, &vertices_vbo);
        glGenBuffers(1, &indices_vbo);

        std::vector<VertexType> vertex_data{
            {{-1, -1}, {0, 0}},
            {{-1,  1}, {0, 1}},
            {{ 1, -1}, {1, 0}},
            {{ 1,  1}, {1, 1}},
        };
        std::vector<uint16_t> index_data{0, 1, 2, 1, 3, 2};

        glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(VertexType) * vertex_data.size(), vertex_data.data(), GL_DYNAMIC_DRAW);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t) * index_data.size(), index_data.data(), GL_DYNAMIC_DRAW);
    }
    else
    {
        glBindBuffer(GL_ARRAY_BUFFER, vertices_vbo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
    }

    glVertexAttribPointer(shader->getAttributeLocation("a_position"), 2, GL_FLOAT, GL_FALSE, static_cast<GLsizei>(sizeof(VertexType)), (void*)offsetof(VertexType, first));
    glEnableVertexAttribArray(shader->getAttributeLocation("a_position"));
    glVertexAttribPointer(shader->getAttributeLocation("a_texcoords"), 2, GL_FLOAT, GL_FALSE, static_cast<GLsizei>(sizeof(VertexType)), (void*)offsetof(VertexType, second));
    glEnableVertexAttribArray(shader->getAttributeLocation("a_texcoords"));

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);

    glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_NONE);
}

void PostProcessor::setUniform(string name, float value)
{
    uniforms[name] = value;
}

bool PostProcessor::onPointerMove(glm::vec2 position, sp::io::Pointer::ID id)
{
    return chain->onPointerMove(position, id);
}

void PostProcessor::onPointerLeave(sp::io::Pointer::ID id)
{
    chain->onPointerLeave(id);
}

bool PostProcessor::onPointerDown(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id)
{
    return chain->onPointerDown(button, position, id);
}

void PostProcessor::onPointerDrag(glm::vec2 position, sp::io::Pointer::ID id)
{
    chain->onPointerDrag(position, id);
}

void PostProcessor::onPointerUp(glm::vec2 position, sp::io::Pointer::ID id)
{
    chain->onPointerUp(position, id);
}

void PostProcessor::onTextInput(const string& text)
{
    chain->onTextInput(text);
}

void PostProcessor::onTextInput(sp::TextInputEvent e)
{
    chain->onTextInput(e);
}
<|endoftext|>


<commit_before>#include "EntityEditor.hpp"

#include <Engine/Component/Animation.hpp>
#include <Engine/Component/Physics.hpp>
#include <Engine/Component/Mesh.hpp>
#include <Engine/Component/Lens.hpp>
#include <Engine/Component/Material.hpp>
#include <Engine/Component/DirectionalLight.hpp>
#include <Engine/Component/PointLight.hpp>
#include <Engine/Component/SpotLight.hpp>
#include <Engine/Component/Listener.hpp>
#include <Engine/Component/Script.hpp>
#include <Engine/Component/SoundSource.hpp>
#include <Engine/Component/ParticleEmitter.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Geometry/Model.hpp>
#include <Engine/Geometry/RiggedModel.hpp>
#include <Engine/Texture/Texture2D.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ScriptManager.hpp>

#include "../../Util/EditorSettings.hpp"
#include "../FileSelector.hpp"
#include "../../ImGui/Draggable.hpp"

using namespace GUI;

EntityEditor::EntityEditor() {
    name[0] = '\0';
    AddEditor<Component::Animation>("Animation", std::bind(&EntityEditor::AnimationEditor, this, std::placeholders::_1));
    AddEditor<Component::Physics>("Physics", std::bind(&EntityEditor::PhysicsEditor, this, std::placeholders::_1));
    AddEditor<Component::Mesh>("Mesh", std::bind(&EntityEditor::MeshEditor, this, std::placeholders::_1));
    AddEditor<Component::Lens>("Lens", std::bind(&EntityEditor::LensEditor, this, std::placeholders::_1));
    AddEditor<Component::Material>("Material", std::bind(&EntityEditor::MaterialEditor, this, std::placeholders::_1));
    AddEditor<Component::DirectionalLight>("Directional light", std::bind(&EntityEditor::DirectionalLightEditor, this, std::placeholders::_1));
    AddEditor<Component::PointLight>("Point light", std::bind(&EntityEditor::PointLightEditor, this, std::placeholders::_1));
    AddEditor<Component::SpotLight>("Spot light", std::bind(&EntityEditor::SpotLightEditor, this, std::placeholders::_1));
    AddEditor<Component::Listener>("Listener", std::bind(&EntityEditor::ListenerEditor, this, std::placeholders::_1));
    AddEditor<Component::Script>("Script", std::bind(&EntityEditor::ScriptEditor, this, std::placeholders::_1));
    AddEditor<Component::SoundSource>("Sound source", std::bind(&EntityEditor::SoundSourceEditor, this, std::placeholders::_1));
    AddEditor<Component::ParticleEmitter>("Particle emitter", std::bind(&EntityEditor::ParticleEmitterEditor, this, std::placeholders::_1));
}

EntityEditor::~EntityEditor() {

}

void EntityEditor::Show() {
    if (ImGui::Begin(("Entity: " + entity->name + "###" + std::to_string(reinterpret_cast<uintptr_t>(entity))).c_str(), &visible)) {
        ImGui::InputText("Name", name, 128);
        entity->name = name;
        ImGui::Text("Transform");
        ImGui::Indent();
        ImGui::DraggableVec3("Position", entity->position);
        ImGui::DraggableVec3("Rotation", entity->rotation);
        ImGui::DraggableVec3("Scale", entity->scale);
        ImGui::Unindent();
        if (!entity->IsScene()) {
            if (ImGui::Button("Add component"))
                ImGui::OpenPopup("Add component");

            if (ImGui::BeginPopup("Add component")) {
                ImGui::Text("Components");
                ImGui::Separator();

                for (Editor& editor : editors) {
                    editor.addFunction();
                }

                ImGui::EndPopup();
            }

            for (Editor& editor : editors) {
                editor.editFunction();
            }
        }
    }

    ImGui::End();
}

void EntityEditor::SetEntity(Entity* entity) {
    this->entity = entity;
    strcpy(name, entity->name.c_str());
}

bool EntityEditor::ShowsEntity(Entity* entity) {
    return this->entity == entity;
}

bool EntityEditor::IsVisible() const {
    return visible;
}

void EntityEditor::SetVisible(bool visible) {
    this->visible = visible;
}

void EntityEditor::AnimationEditor(Component::Animation* animation) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Animation"))
        ImGui::OpenPopup("Select model##Animation");

    if (ImGui::BeginPopup("Select model##Animation")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Hymn().models) {
            if (ImGui::Selectable(model->name.c_str()))
                animation->riggedModel = dynamic_cast<Geometry::RiggedModel*>(model);
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::PhysicsEditor(Component::Physics* physics) {
    ImGui::Text("Positional");
    ImGui::Indent();
    ImGui::DraggableVec3("Velocity", physics->velocity);
    ImGui::DraggableFloat("Max velocity", physics->maxVelocity, 0.0f);
    ImGui::DraggableVec3("Acceleration", physics->acceleration);
    ImGui::DraggableFloat("Velocity drag factor", physics->velocityDragFactor);
    ImGui::DraggableFloat("Gravity factor", physics->gravityFactor);
    ImGui::Unindent();
    ImGui::Text("Angular");
    ImGui::Indent();
    ImGui::DraggableVec3("Angular velocity", physics->angularVelocity);
    ImGui::DraggableFloat("Max angular velocity", physics->maxAngularVelocity, 0.0f);
    ImGui::DraggableVec3("Angular acceleration", physics->angularAcceleration);
    ImGui::DraggableFloat("Angular drag factor", physics->angularDragFactor);
    ImGui::DraggableVec3("Moment of inertia", physics->momentOfInertia);
    ImGui::Unindent();

}

void EntityEditor::MeshEditor(Component::Mesh* mesh) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Mesh"))
        ImGui::OpenPopup("Select model##Mesh");

    if (ImGui::BeginPopup("Select model##Mesh")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Hymn().models) {
            if (ImGui::Selectable(model->name.c_str()))
                mesh->geometry = model;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::LensEditor(Component::Lens* lens) {
    ImGui::Indent();
    ImGui::DraggableFloat("Field of view", lens->fieldOfView, 0.0f, 180.f);
    ImGui::DraggableFloat("Z near", lens->zNear, 0.0f);
    ImGui::DraggableFloat("Z far", lens->zFar, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::MaterialEditor(Component::Material* material) {
    // Diffuse
    ImGui::Text("Diffuse");
    ImGui::Indent();
    if (material->diffuse->IsLoaded())
        ImGui::Image((void*) material->diffuse->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select diffuse texture"))
        ImGui::OpenPopup("Select diffuse texture");

    if (ImGui::BeginPopup("Select diffuse texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->diffuse = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Normal
    ImGui::Text("Normal");
    ImGui::Indent();
    if (material->normal->IsLoaded())
        ImGui::Image((void*) material->normal->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select normal texture"))
        ImGui::OpenPopup("Select normal texture");

    if (ImGui::BeginPopup("Select normal texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->normal = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Specular
    ImGui::Text("Specular");
    ImGui::Indent();
    if (material->specular->IsLoaded())
        ImGui::Image((void*) material->specular->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select specular texture"))
        ImGui::OpenPopup("Select specular texture");

    if (ImGui::BeginPopup("Select specular texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->specular = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Glow
    ImGui::Text("Glow");
    ImGui::Indent();
    if (material->glow->IsLoaded())
        ImGui::Image((void*) material->glow->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select glow texture"))
        ImGui::OpenPopup("Select glow texture");

    if (ImGui::BeginPopup("Select glow texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->glow = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::DirectionalLightEditor(Component::DirectionalLight* directionalLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &directionalLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", directionalLight->ambientCoefficient, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::PointLightEditor(Component::PointLight* pointLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &pointLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", pointLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", pointLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", pointLight->intensity, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::SpotLightEditor(Component::SpotLight* spotLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &spotLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", spotLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", spotLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", spotLight->intensity, 0.0f);
    ImGui::DraggableFloat("Cone angle", spotLight->coneAngle, 0.0f, 180.f);
    ImGui::Unindent();
}

void EntityEditor::ListenerEditor(Component::Listener* listener) {

}

void EntityEditor::ScriptEditor(Component::Script* script) {
    ImGui::Indent();
    if(script->scriptFile != nullptr)
        ImGui::Text(script->scriptFile->name.c_str());
    else
        ImGui::Text("No script loaded");

    if (ImGui::Button("Select script"))
        ImGui::OpenPopup("Select script");

    if (ImGui::BeginPopup("Select script")) {
        ImGui::Text("Scripts");
        ImGui::Separator();

        for (ScriptFile* scriptFile : Hymn().scripts) {
            if (ImGui::Selectable(scriptFile->name.c_str()))
                script->scriptFile = scriptFile;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::SoundSourceEditor(Component::SoundSource* soundSource) {
    ImGui::Text("Sound");
    ImGui::Indent();
    if (ImGui::Button("Select sound"))
        ImGui::OpenPopup("Select sound");

    if (ImGui::BeginPopup("Select sound")) {
        ImGui::Text("Sounds");
        ImGui::Separator();

        for (Audio::SoundBuffer* sound : Hymn().sounds) {
            if (ImGui::Selectable(sound->name.c_str()))
                soundSource->soundBuffer = sound;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
    ImGui::Text("Sound properties");
    ImGui::Indent();
    ImGui::DraggableFloat("Pitch", soundSource->pitch, 0.0f);
    ImGui::DraggableFloat("Gain", soundSource->gain, 0.0f);
    ImGui::Checkbox("Loop", &soundSource->loop);
    ImGui::Unindent();
}

void EntityEditor::ParticleEmitterEditor(Component::ParticleEmitter* particleEmitter) {
    ImGui::Text("Particle");
    ImGui::Indent();
    int rows = Managers().particleManager->GetTextureAtlasRows();
    float column = static_cast<float>(particleEmitter->particleType.textureIndex % rows);
    float row = static_cast<float>(particleEmitter->particleType.textureIndex / rows);
    ImGui::Image((void*) Managers().particleManager->GetTextureAtlas()->GetTextureID(), ImVec2(128, 128), ImVec2(column / rows, row / rows), ImVec2((column + 1.f) / rows, (row + 1.f) / rows));
    ImGui::InputInt("Texture index", &particleEmitter->particleType.textureIndex);
    ImGui::ColorEdit3("Color", &particleEmitter->particleType.color[0]);
    ImGui::DraggableVec3("Min velocity", particleEmitter->particleType.minVelocity);
    ImGui::DraggableVec3("Max velocity", particleEmitter->particleType.maxVelocity);
    ImGui::DraggableFloat("Average lifetime", particleEmitter->particleType.averageLifetime, 0.0f);
    ImGui::DraggableFloat("Lifetime variance", particleEmitter->particleType.lifetimeVariance, 0.0f);
    ImGui::DraggableVec2("Average size", particleEmitter->particleType.averageSize, 0.0f);
    ImGui::DraggableVec2("Size variance", particleEmitter->particleType.sizeVariance, 0.0f);
    ImGui::Checkbox("Uniform scaling", &particleEmitter->particleType.uniformScaling);
    ImGui::DraggableFloat("Start alpha", particleEmitter->particleType.startAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("Mid alpha", particleEmitter->particleType.midAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("End alpha", particleEmitter->particleType.endAlpha, 0.0f, 1.0f);
    ImGui::Unindent();

    ImGui::Text("Emitter");
    ImGui::Indent();
    ImGui::DraggableFloat("Average emit time", particleEmitter->averageEmitTime, 0.0f);
    ImGui::DraggableFloat("Emit time variance", particleEmitter->emitTimeVariance, 0.0f);

    const char* items[] = { "Point", "Cuboid" };
    int item = static_cast<int>(particleEmitter->emitterType);
    if (ImGui::Combo("Emitter type", &item, items, 2))
        particleEmitter->emitterType = static_cast<Component::ParticleEmitter::EmitterType>(item);

    if (particleEmitter->emitterType == Component::ParticleEmitter::CUBOID)
        ImGui::DraggableVec3("Size", particleEmitter->size);

    ImGui::Unindent();

    ImGui::Text("Preview");
    ImGui::Indent();
    ImGui::Checkbox("Simulate", &particleEmitter->preview);
    ImGui::Unindent();
}
<commit_msg>Test of help markers.<commit_after>#include "EntityEditor.hpp"

#include <Engine/Component/Animation.hpp>
#include <Engine/Component/Physics.hpp>
#include <Engine/Component/Mesh.hpp>
#include <Engine/Component/Lens.hpp>
#include <Engine/Component/Material.hpp>
#include <Engine/Component/DirectionalLight.hpp>
#include <Engine/Component/PointLight.hpp>
#include <Engine/Component/SpotLight.hpp>
#include <Engine/Component/Listener.hpp>
#include <Engine/Component/Script.hpp>
#include <Engine/Component/SoundSource.hpp>
#include <Engine/Component/ParticleEmitter.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Geometry/Model.hpp>
#include <Engine/Geometry/RiggedModel.hpp>
#include <Engine/Texture/Texture2D.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ScriptManager.hpp>
#include "../GuiHelpers.hpp"

#include "../../Util/EditorSettings.hpp"
#include "../FileSelector.hpp"
#include "../../ImGui/Draggable.hpp"

using namespace GUI;

EntityEditor::EntityEditor() {
    name[0] = '\0';
    AddEditor<Component::Animation>("Animation", std::bind(&EntityEditor::AnimationEditor, this, std::placeholders::_1));
    AddEditor<Component::Physics>("Physics", std::bind(&EntityEditor::PhysicsEditor, this, std::placeholders::_1));
    AddEditor<Component::Mesh>("Mesh", std::bind(&EntityEditor::MeshEditor, this, std::placeholders::_1));
    AddEditor<Component::Lens>("Lens", std::bind(&EntityEditor::LensEditor, this, std::placeholders::_1));
    AddEditor<Component::Material>("Material", std::bind(&EntityEditor::MaterialEditor, this, std::placeholders::_1));
    AddEditor<Component::DirectionalLight>("Directional light", std::bind(&EntityEditor::DirectionalLightEditor, this, std::placeholders::_1));
    AddEditor<Component::PointLight>("Point light", std::bind(&EntityEditor::PointLightEditor, this, std::placeholders::_1));
    AddEditor<Component::SpotLight>("Spot light", std::bind(&EntityEditor::SpotLightEditor, this, std::placeholders::_1));
    AddEditor<Component::Listener>("Listener", std::bind(&EntityEditor::ListenerEditor, this, std::placeholders::_1));
    AddEditor<Component::Script>("Script", std::bind(&EntityEditor::ScriptEditor, this, std::placeholders::_1));
    AddEditor<Component::SoundSource>("Sound source", std::bind(&EntityEditor::SoundSourceEditor, this, std::placeholders::_1));
    AddEditor<Component::ParticleEmitter>("Particle emitter", std::bind(&EntityEditor::ParticleEmitterEditor, this, std::placeholders::_1));
}

EntityEditor::~EntityEditor() {

}

void EntityEditor::Show() {
    if (ImGui::Begin(("Entity: " + entity->name + "###" + std::to_string(reinterpret_cast<uintptr_t>(entity))).c_str(), &visible)) {
        ImGui::InputText("Name", name, 128);
        entity->name = name;
        ImGui::Text("Transform");
        ImGui::ShowHelpMarker("The entities position, rotation and scale.", 75.f);
        ImGui::Indent();
        ImGui::DraggableVec3("Position", entity->position);
        ImGui::DraggableVec3("Rotation", entity->rotation);
        ImGui::DraggableVec3("Scale", entity->scale);
        ImGui::Unindent();
        if (!entity->IsScene()) {
            if (ImGui::Button("Add component"))
                ImGui::OpenPopup("Add component");

            if (ImGui::BeginPopup("Add component")) {
                ImGui::Text("Components");
                ImGui::Separator();

                for (Editor& editor : editors) {
                    editor.addFunction();
                }

                ImGui::EndPopup();
            }

            for (Editor& editor : editors) {
                editor.editFunction();
            }
        }
    }

    ImGui::End();
}

void EntityEditor::SetEntity(Entity* entity) {
    this->entity = entity;
    strcpy(name, entity->name.c_str());
}

bool EntityEditor::ShowsEntity(Entity* entity) {
    return this->entity == entity;
}

bool EntityEditor::IsVisible() const {
    return visible;
}

void EntityEditor::SetVisible(bool visible) {
    this->visible = visible;
}

void EntityEditor::AnimationEditor(Component::Animation* animation) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Animation"))
        ImGui::OpenPopup("Select model##Animation");

    if (ImGui::BeginPopup("Select model##Animation")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Hymn().models) {
            if (ImGui::Selectable(model->name.c_str()))
                animation->riggedModel = dynamic_cast<Geometry::RiggedModel*>(model);
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::PhysicsEditor(Component::Physics* physics) {
    ImGui::Text("Positional");
    ImGui::Indent();
    ImGui::DraggableVec3("Velocity", physics->velocity);
    ImGui::DraggableFloat("Max velocity", physics->maxVelocity, 0.0f);
    ImGui::DraggableVec3("Acceleration", physics->acceleration);
    ImGui::DraggableFloat("Velocity drag factor", physics->velocityDragFactor);
    ImGui::DraggableFloat("Gravity factor", physics->gravityFactor);
    ImGui::Unindent();
    ImGui::Text("Angular");
    ImGui::Indent();
    ImGui::DraggableVec3("Angular velocity", physics->angularVelocity);
    ImGui::DraggableFloat("Max angular velocity", physics->maxAngularVelocity, 0.0f);
    ImGui::DraggableVec3("Angular acceleration", physics->angularAcceleration);
    ImGui::DraggableFloat("Angular drag factor", physics->angularDragFactor);
    ImGui::DraggableVec3("Moment of inertia", physics->momentOfInertia);
    ImGui::Unindent();

}

void EntityEditor::MeshEditor(Component::Mesh* mesh) {
    ImGui::Indent();
    if (ImGui::Button("Select model##Mesh"))
        ImGui::OpenPopup("Select model##Mesh");

    if (ImGui::BeginPopup("Select model##Mesh")) {
        ImGui::Text("Models");
        ImGui::Separator();

        for (Geometry::Model* model : Hymn().models) {
            if (ImGui::Selectable(model->name.c_str()))
                mesh->geometry = model;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::LensEditor(Component::Lens* lens) {
    ImGui::Indent();
    ImGui::DraggableFloat("Field of view", lens->fieldOfView, 0.0f, 180.f);
    ImGui::DraggableFloat("Z near", lens->zNear, 0.0f);
    ImGui::DraggableFloat("Z far", lens->zFar, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::MaterialEditor(Component::Material* material) {
    // Diffuse
    ImGui::Text("Diffuse");
    ImGui::Indent();
    if (material->diffuse->IsLoaded())
        ImGui::Image((void*) material->diffuse->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select diffuse texture"))
        ImGui::OpenPopup("Select diffuse texture");

    if (ImGui::BeginPopup("Select diffuse texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->diffuse = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Normal
    ImGui::Text("Normal");
    ImGui::Indent();
    if (material->normal->IsLoaded())
        ImGui::Image((void*) material->normal->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select normal texture"))
        ImGui::OpenPopup("Select normal texture");

    if (ImGui::BeginPopup("Select normal texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->normal = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Specular
    ImGui::Text("Specular");
    ImGui::Indent();
    if (material->specular->IsLoaded())
        ImGui::Image((void*) material->specular->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select specular texture"))
        ImGui::OpenPopup("Select specular texture");

    if (ImGui::BeginPopup("Select specular texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->specular = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();

    // Glow
    ImGui::Text("Glow");
    ImGui::Indent();
    if (material->glow->IsLoaded())
        ImGui::Image((void*) material->glow->GetTextureID(), ImVec2(128, 128));

    if (ImGui::Button("Select glow texture"))
        ImGui::OpenPopup("Select glow texture");

    if (ImGui::BeginPopup("Select glow texture")) {
        ImGui::Text("Textures");
        ImGui::Separator();

        for (Texture2D* texture : Hymn().textures) {
            if (ImGui::Selectable(texture->name.c_str()))
                material->glow = texture;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::DirectionalLightEditor(Component::DirectionalLight* directionalLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &directionalLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", directionalLight->ambientCoefficient, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::PointLightEditor(Component::PointLight* pointLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &pointLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", pointLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", pointLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", pointLight->intensity, 0.0f);
    ImGui::Unindent();
}

void EntityEditor::SpotLightEditor(Component::SpotLight* spotLight) {
    ImGui::Indent();
    ImGui::InputFloat3("Color", &spotLight->color[0]);
    ImGui::DraggableFloat("Ambient coefficient", spotLight->ambientCoefficient, 0.0f);
    ImGui::DraggableFloat("Attenuation", spotLight->attenuation, 0.0f);
    ImGui::DraggableFloat("Intensity", spotLight->intensity, 0.0f);
    ImGui::DraggableFloat("Cone angle", spotLight->coneAngle, 0.0f, 180.f);
    ImGui::Unindent();
}

void EntityEditor::ListenerEditor(Component::Listener* listener) {

}

void EntityEditor::ScriptEditor(Component::Script* script) {
    ImGui::Indent();
    if(script->scriptFile != nullptr)
        ImGui::Text(script->scriptFile->name.c_str());
    else
        ImGui::Text("No script loaded");

    if (ImGui::Button("Select script"))
        ImGui::OpenPopup("Select script");

    if (ImGui::BeginPopup("Select script")) {
        ImGui::Text("Scripts");
        ImGui::Separator();

        for (ScriptFile* scriptFile : Hymn().scripts) {
            if (ImGui::Selectable(scriptFile->name.c_str()))
                script->scriptFile = scriptFile;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
}

void EntityEditor::SoundSourceEditor(Component::SoundSource* soundSource) {
    ImGui::Text("Sound");
    ImGui::Indent();
    if (ImGui::Button("Select sound"))
        ImGui::OpenPopup("Select sound");

    if (ImGui::BeginPopup("Select sound")) {
        ImGui::Text("Sounds");
        ImGui::Separator();

        for (Audio::SoundBuffer* sound : Hymn().sounds) {
            if (ImGui::Selectable(sound->name.c_str()))
                soundSource->soundBuffer = sound;
        }

        ImGui::EndPopup();
    }
    ImGui::Unindent();
    ImGui::Text("Sound properties");
    ImGui::Indent();
    ImGui::DraggableFloat("Pitch", soundSource->pitch, 0.0f);
    ImGui::DraggableFloat("Gain", soundSource->gain, 0.0f);
    ImGui::Checkbox("Loop", &soundSource->loop);
    ImGui::Unindent();
}

void EntityEditor::ParticleEmitterEditor(Component::ParticleEmitter* particleEmitter) {
    ImGui::Text("Particle");
    ImGui::Indent();
    int rows = Managers().particleManager->GetTextureAtlasRows();
    float column = static_cast<float>(particleEmitter->particleType.textureIndex % rows);
    float row = static_cast<float>(particleEmitter->particleType.textureIndex / rows);
    ImGui::Image((void*) Managers().particleManager->GetTextureAtlas()->GetTextureID(), ImVec2(128, 128), ImVec2(column / rows, row / rows), ImVec2((column + 1.f) / rows, (row + 1.f) / rows));
    ImGui::InputInt("Texture index", &particleEmitter->particleType.textureIndex);
    ImGui::ColorEdit3("Color", &particleEmitter->particleType.color[0]);
    ImGui::DraggableVec3("Min velocity", particleEmitter->particleType.minVelocity);
    ImGui::DraggableVec3("Max velocity", particleEmitter->particleType.maxVelocity);
    ImGui::DraggableFloat("Average lifetime", particleEmitter->particleType.averageLifetime, 0.0f);
    ImGui::DraggableFloat("Lifetime variance", particleEmitter->particleType.lifetimeVariance, 0.0f);
    ImGui::DraggableVec2("Average size", particleEmitter->particleType.averageSize, 0.0f);
    ImGui::DraggableVec2("Size variance", particleEmitter->particleType.sizeVariance, 0.0f);
    ImGui::Checkbox("Uniform scaling", &particleEmitter->particleType.uniformScaling);
    ImGui::DraggableFloat("Start alpha", particleEmitter->particleType.startAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("Mid alpha", particleEmitter->particleType.midAlpha, 0.0f, 1.0f);
    ImGui::DraggableFloat("End alpha", particleEmitter->particleType.endAlpha, 0.0f, 1.0f);
    ImGui::Unindent();

    ImGui::Text("Emitter");
    ImGui::Indent();
    ImGui::DraggableFloat("Average emit time", particleEmitter->averageEmitTime, 0.0f);
    ImGui::DraggableFloat("Emit time variance", particleEmitter->emitTimeVariance, 0.0f);

    const char* items[] = { "Point", "Cuboid" };
    int item = static_cast<int>(particleEmitter->emitterType);
    if (ImGui::Combo("Emitter type", &item, items, 2))
        particleEmitter->emitterType = static_cast<Component::ParticleEmitter::EmitterType>(item);

    if (particleEmitter->emitterType == Component::ParticleEmitter::CUBOID)
        ImGui::DraggableVec3("Size", particleEmitter->size);

    ImGui::Unindent();

    ImGui::Text("Preview");
    ImGui::Indent();
    ImGui::Checkbox("Simulate", &particleEmitter->preview);
    ImGui::Unindent();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactiondesc.h"

#include "bitcoinunits.h"
#include "guiutil.h"
#include "paymentserver.h"
#include "transactionrecord.h"

#include "base58.h"
#include "consensus/consensus.h"
#include "validation.h"
#include "script/script.h"
#include "timedata.h"
#include "util.h"
#include "wallet/db.h"
#include "wallet/wallet.h"

#include <stdint.h>
#include <string>

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);
    if (!CheckFinalTx(wtx))
    {
        if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (nDepth < 0)
            return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth == 0)
            return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
        else if (nDepth < 6)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);
    strHTML.reserve(4000);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
    CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
    CAmount nNet = nCredit - nDebit;

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
    int nRequests = wtx.GetRequestCount();
    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");
        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }
    strHTML += "
";

    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    //
    // From
    //
    if (wtx.IsCoinBase())
    {
        strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
    }
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
    {
        // Online transaction
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
    }
    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            if (IsValidDestinationString(rec->address)) {
                CTxDestination address = DecodeDestination(rec->address);
                if (wallet->mapAddressBook.count(address))
                {
                    strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                    strHTML += "" + tr("To") + ": ";
                    strHTML += GUIUtil::HtmlEscape(rec->address);
                    QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
                    if (!wallet->mapAddressBook[address].name.empty())
                        strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
                    else
                        strHTML += " (" + addressOwned + ")";
                    strHTML += "
";
                }
            }
        }
    }

    //
    // To
    //
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];
        strHTML += "" + tr("To") + ": ";
        CTxDestination dest = DecodeDestination(strAddress);
        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    //
    // Amount
    //
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        //
        // Coinbase
        //
        CAmount nUnmatured = 0;
        for (const CTxOut& txout : wtx.tx->vout)
            nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
        strHTML += "" + tr("Credit") + ": ";
        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
        else
            strHTML += "(" + tr("not accepted") + ")";
        strHTML += "
";
    }
    else if (nNet > 0)
    {
        //
        // Credit
        //
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "
";
    }
    else
    {
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        for (const CTxIn& txin : wtx.tx->vin)
        {
            isminetype mine = wallet->IsMine(txin);
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        for (const CTxOut& txout : wtx.tx->vout)
        {
            isminetype mine = wallet->IsMine(txout);
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe)
        {
            if(fAllFromMe & ISMINE_WATCH_ONLY)
                strHTML += "" + tr("From") + ": " + tr("watch-only") + "
";

            //
            // Debit
            //
            for (const CTxOut& txout : wtx.tx->vout)
            {
                // Ignore change
                isminetype toSelf = wallet->IsMine(txout);
                if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
                        strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
                        if(toSelf == ISMINE_SPENDABLE)
                            strHTML += " (own address)";
                        else if(toSelf & ISMINE_WATCH_ONLY)
                            strHTML += " (watch-only)";
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "
";
                if(toSelf)
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                CAmount nChange = wtx.GetChange();
                CAmount nValue = nCredit - nChange;
                strHTML += "" + tr("Total debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "
";
                strHTML += "" + tr("Total credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "
";
            }

            CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "
";
        }
        else
        {
            //
            // Mixed debit transaction
            //
            for (const CTxIn& txin : wtx.tx->vin)
                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
";
            for (const CTxOut& txout : wtx.tx->vout)
                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "
";

    //
    // Message
    //
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("Transaction ID") + ": " + rec->getTxID() + "
";
    strHTML += "" + tr("Transaction total size") + ": " + QString::number(wtx.tx->GetTotalSize()) + " bytes
";
    strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
";

    // Message from normal bitcoin:URI (bitcoin:123...?message=example)
    for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
        if (r.first == "Message")
            strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(r.second, true) + "
";

    //
    // PaymentRequest info:
    //
    for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
    {
        if (r.first == "PaymentRequest")
        {
            PaymentRequestPlus req;
            req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
            QString merchant;
            if (req.getMerchant(PaymentServer::getCertStore(), merchant))
                strHTML += "" + tr("Merchant") + ": " + GUIUtil::HtmlEscape(merchant) + "
";
        }
    }

    if (wtx.IsCoinBase())
    {
        quint32 numBlocksToMaturity = COINBASE_MATURITY +  1;
        strHTML += "
" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "
";
    }

    //
    // Debug view
    //
    if (logCategories != BCLog::NONE)
    {
        strHTML += "

" + tr("Debug information") + "

";
        for (const CTxIn& txin : wtx.tx->vin)
            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
";
        for (const CTxOut& txout : wtx.tx->vout)
            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
";

        strHTML += "
" + tr("Transaction") + ":
";
        strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);

        strHTML += "
" + tr("Inputs") + ":";
        strHTML += "
";

        for (const CTxIn& txin : wtx.tx->vin)
        {
            COutPoint prevout = txin.prevout;

            Coin prev;
            if(pcoinsTip->GetCoin(prevout, prev))
            {
                {
                    strHTML += "
";
                    const CTxOut &vout = prev.out;
                    CTxDestination address;
                    if (ExtractDestination(vout.scriptPubKey, address))
                    {
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
                        strHTML += QString::fromStdString(EncodeDestination(address));
                    }
                    strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
                    strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "
";
                    strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";
    return strHTML;
}
<commit_msg>Remove duplicate destination decoding<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "transactiondesc.h"

#include "bitcoinunits.h"
#include "guiutil.h"
#include "paymentserver.h"
#include "transactionrecord.h"

#include "base58.h"
#include "consensus/consensus.h"
#include "validation.h"
#include "script/script.h"
#include "timedata.h"
#include "util.h"
#include "wallet/db.h"
#include "wallet/wallet.h"

#include <stdint.h>
#include <string>

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);
    if (!CheckFinalTx(wtx))
    {
        if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (nDepth < 0)
            return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth == 0)
            return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
        else if (nDepth < 6)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionRecord *rec, int unit)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);
    strHTML.reserve(4000);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    CAmount nCredit = wtx.GetCredit(ISMINE_ALL);
    CAmount nDebit = wtx.GetDebit(ISMINE_ALL);
    CAmount nNet = nCredit - nDebit;

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
    int nRequests = wtx.GetRequestCount();
    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");
        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }
    strHTML += "
";

    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    //
    // From
    //
    if (wtx.IsCoinBase())
    {
        strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
    }
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
    {
        // Online transaction
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
    }
    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            CTxDestination address = DecodeDestination(rec->address);
            if (IsValidDestination(address)) {
                if (wallet->mapAddressBook.count(address))
                {
                    strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                    strHTML += "" + tr("To") + ": ";
                    strHTML += GUIUtil::HtmlEscape(rec->address);
                    QString addressOwned = (::IsMine(*wallet, address) == ISMINE_SPENDABLE) ? tr("own address") : tr("watch-only");
                    if (!wallet->mapAddressBook[address].name.empty())
                        strHTML += " (" + addressOwned + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")";
                    else
                        strHTML += " (" + addressOwned + ")";
                    strHTML += "
";
                }
            }
        }
    }

    //
    // To
    //
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];
        strHTML += "" + tr("To") + ": ";
        CTxDestination dest = DecodeDestination(strAddress);
        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    //
    // Amount
    //
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        //
        // Coinbase
        //
        CAmount nUnmatured = 0;
        for (const CTxOut& txout : wtx.tx->vout)
            nUnmatured += wallet->GetCredit(txout, ISMINE_ALL);
        strHTML += "" + tr("Credit") + ": ";
        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
        else
            strHTML += "(" + tr("not accepted") + ")";
        strHTML += "
";
    }
    else if (nNet > 0)
    {
        //
        // Credit
        //
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "
";
    }
    else
    {
        isminetype fAllFromMe = ISMINE_SPENDABLE;
        for (const CTxIn& txin : wtx.tx->vin)
        {
            isminetype mine = wallet->IsMine(txin);
            if(fAllFromMe > mine) fAllFromMe = mine;
        }

        isminetype fAllToMe = ISMINE_SPENDABLE;
        for (const CTxOut& txout : wtx.tx->vout)
        {
            isminetype mine = wallet->IsMine(txout);
            if(fAllToMe > mine) fAllToMe = mine;
        }

        if (fAllFromMe)
        {
            if(fAllFromMe & ISMINE_WATCH_ONLY)
                strHTML += "" + tr("From") + ": " + tr("watch-only") + "
";

            //
            // Debit
            //
            for (const CTxOut& txout : wtx.tx->vout)
            {
                // Ignore change
                isminetype toSelf = wallet->IsMine(txout);
                if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
                        strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
                        if(toSelf == ISMINE_SPENDABLE)
                            strHTML += " (own address)";
                        else if(toSelf & ISMINE_WATCH_ONLY)
                            strHTML += " (watch-only)";
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "
";
                if(toSelf)
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                CAmount nChange = wtx.GetChange();
                CAmount nValue = nCredit - nChange;
                strHTML += "" + tr("Total debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "
";
                strHTML += "" + tr("Total credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "
";
            }

            CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "
";
        }
        else
        {
            //
            // Mixed debit transaction
            //
            for (const CTxIn& txin : wtx.tx->vin)
                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
";
            for (const CTxOut& txout : wtx.tx->vout)
                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "
";

    //
    // Message
    //
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("Transaction ID") + ": " + rec->getTxID() + "
";
    strHTML += "" + tr("Transaction total size") + ": " + QString::number(wtx.tx->GetTotalSize()) + " bytes
";
    strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
";

    // Message from normal bitcoin:URI (bitcoin:123...?message=example)
    for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
        if (r.first == "Message")
            strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(r.second, true) + "
";

    //
    // PaymentRequest info:
    //
    for (const std::pair<std::string, std::string>& r : wtx.vOrderForm)
    {
        if (r.first == "PaymentRequest")
        {
            PaymentRequestPlus req;
            req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
            QString merchant;
            if (req.getMerchant(PaymentServer::getCertStore(), merchant))
                strHTML += "" + tr("Merchant") + ": " + GUIUtil::HtmlEscape(merchant) + "
";
        }
    }

    if (wtx.IsCoinBase())
    {
        quint32 numBlocksToMaturity = COINBASE_MATURITY +  1;
        strHTML += "
" + tr("Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.").arg(QString::number(numBlocksToMaturity)) + "
";
    }

    //
    // Debug view
    //
    if (logCategories != BCLog::NONE)
    {
        strHTML += "

" + tr("Debug information") + "

";
        for (const CTxIn& txin : wtx.tx->vin)
            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
";
        for (const CTxOut& txout : wtx.tx->vout)
            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
";

        strHTML += "
" + tr("Transaction") + ":
";
        strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);

        strHTML += "
" + tr("Inputs") + ":";
        strHTML += "
";

        for (const CTxIn& txin : wtx.tx->vin)
        {
            COutPoint prevout = txin.prevout;

            Coin prev;
            if(pcoinsTip->GetCoin(prevout, prev))
            {
                {
                    strHTML += "
";
                    const CTxOut &vout = prev.out;
                    CTxDestination address;
                    if (ExtractDestination(vout.scriptPubKey, address))
                    {
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
                        strHTML += QString::fromStdString(EncodeDestination(address));
                    }
                    strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
                    strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "
";
                    strHTML = strHTML + " IsWatchOnly=" + (wallet->IsMine(vout) & ISMINE_WATCH_ONLY ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";
    return strHTML;
}
<|endoftext|>


<commit_before>#include "EulerCycle.h"
#include <cassert>
#include <stack>

static bool HasEulerCycle(int g[MAX][MAX], int n) {
  for (int i = 0; i < n; i++) {
    int degree = 0;
    for (int j = 0; j < n; j++) {
      if (g[i][j] > 0) {
        degree++;
      }
    }
    if (degree % 2 == 1) {
      return false;
    }
  }
  return true;
}

static int MaxDegree(int g[MAX][MAX], int *degree, int beg) {
  int d_max(0), index(-1);
  for (int i = 0; i < g.g_cnt; ++i) {
    if (i == beg)
      continue;
    //在beg相邻节点中找出最大度数节点
    if (g.g_m[beg][i] and d_max < degree[i])
      d_max = degree[i], index = i;
  }
  return (index);
}

static void Dfs(int g[MAX][MAX], int *degree, int beg, std::stack<int> &path) {
  path.push(beg);
  //找出beg相邻节点中度数最大的节点 对他进行下一次dfs
  int d_max = max_degree(g, degree, beg);
  //终止递归条件 若beg没有邻节点则递归搜索结束
  if (d_max == -1)
    return;

  //每次从当前节点向外找一条新的边
  //并将当前走过的路删除
  g.g_m[beg][d_max] = 0;
  g.g_m[d_max][beg] = 0;
  //当前节点和下一个节点的度数也减1
  --degree[beg];
  --degree[d_max];
  dfs_loop(g, degree, d_max, path);
}

std::pair<bool, std::vector<int>> EulerCycle(int g[MAX][MAX], int n) {
  if (!HasEulerCycle(g, n)) {
    return std::make_pair(false, std::vector<int>());
  }
}

bool loop_exist(int *degree, int n);
void dfs_loop(graph_matrix g, int *degree, int beg, stack<int> &path);
int max_degree(graph_matrix g, int *degree, int beg);

bool euler_loop(
    graph_matrix g,
    stack<int>
        &path) { //邻接矩阵中g.g_m[i][j]的值为0或1
                 //指代从节点i到j是否存在一条有向边 判断是否存在欧拉回路
                 //若存在则返回栈path 栈path中从底至顶
                 //逆序存储着欧拉回路的所有顶点下标号
                 //依次对path出栈即可得到欧拉回路
                 //在无向图中不用考虑这个逆序
                 //因为欧拉回路或欧拉路在无向边中可以两个方向走 path初始为空
  int degree[MAX];
  memset(degree, 0, MAX * sizeof(int));
  // degree[i]指代节点i的度数
  for (int i = 0; i < g.g_cnt; ++i)
    for (int j = 0; j < g.g_cnt; ++j)
      degree[i] += g.g_m[i][j];
  if (loop_exist((int *)degree, g.g_cnt)) {
    //判断无向连通图G中是否存在欧拉回路
    dfs_loop(g, degree, 0, path);
    return (true);
  } else
    return (false);
}
bool loop_exist(int *degree, int n) { //判断无向连通图G中是否存在欧拉回路
  for (int i = 0; i < n; ++i)
    //若存在度数为奇数的节点则不存在欧拉回路
    if (degree[i] % 2 == 1)
      return (false);
  return (true);
}
void dfs_loop(graph_matrix g, int *degree, int beg,
              stack<int> &path) { //返回的path中从底至顶
                                  //逆序存储着欧拉回路的所有顶点下标号
                                  //对path出栈即可得到欧拉回路 path初始为空
  path.push(beg);
  //找出beg相邻节点中度数最大的节点 对他进行下一次dfs
  int d_max = max_degree(g, degree, beg);
  //终止递归条件 若beg没有邻节点则递归搜索结束
  if (d_max == -1)
    return;

  //每次从当前节点向外找一条新的边
  //并将当前走过的路删除
  g.g_m[beg][d_max] = 0;
  g.g_m[d_max][beg] = 0;
  //当前节点和下一个节点的度数也减1
  --degree[beg];
  --degree[d_max];
  dfs_loop(g, degree, d_max, path);
}
int max_degree(graph_matrix g, int *degree, int beg) {
  int d_max(0), index(-1);
  for (int i = 0; i < g.g_cnt; ++i) {
    if (i == beg)
      continue;
    //在beg相邻节点中找出最大度数节点
    if (g.g_m[beg][i] and d_max < degree[i])
      d_max = degree[i], index = i;
  }
  return (index);
}

<commit_msg>save code<commit_after>#include "EulerCycle.h"
#include <cassert>
#include <stack>

static bool UndirectedGraphExist(int g[MAX][MAX], int n) {
  for (int i = 0; i < n; i++) {
    int degree = 0;
    for (int j = 0; j < n; j++) {
      if (g[i][j] > 0) {
        degree++;
      }
    }
    if (degree % 2 == 1) {
      return false;
    }
  }
  return true;
}

static int MaxDegree(int g[MAX][MAX], int *degree, int beg) {
  int d_max(0), index(-1);
  for (int i = 0; i < g.g_cnt; ++i) {
    if (i == beg)
      continue;
    //在beg相邻节点中找出最大度数节点
    if (g.g_m[beg][i] and d_max < degree[i])
      d_max = degree[i], index = i;
  }
  return (index);
}

static void Dfs(int g[MAX][MAX], int *degree, int beg, std::stack<int> &path) {
  path.push(beg);
  //找出beg相邻节点中度数最大的节点 对他进行下一次dfs
  int md = MaxDegree(g, degree, beg);
  //终止递归条件 若beg没有邻节点则递归搜索结束
  if (md == -1)
    return;

  //每次从当前节点向外找一条新的边
  //并将当前走过的路删除
  g.g_m[beg][md] = 0;
  g.g_m[md][beg] = 0;
  //当前节点和下一个节点的度数也减1
  degree[beg]--;
  degree[md]-- - ;
  dfs_loop(g, degree, md, path);
}

std::pair<bool, std::vector<int>> EulerCycle(int g[MAX][MAX], int n) {
  if (!UndirectedGraphExist(g, n)) {
    return std::make_pair(false, std::vector<int>());
  }
}

bool loop_exist(int *degree, int n);
void dfs_loop(graph_matrix g, int *degree, int beg, stack<int> &path);
int max_degree(graph_matrix g, int *degree, int beg);

bool euler_loop(
    graph_matrix g,
    stack<int>
        &path) { //邻接矩阵中g.g_m[i][j]的值为0或1
                 //指代从节点i到j是否存在一条有向边 判断是否存在欧拉回路
                 //若存在则返回栈path 栈path中从底至顶
                 //逆序存储着欧拉回路的所有顶点下标号
                 //依次对path出栈即可得到欧拉回路
                 //在无向图中不用考虑这个逆序
                 //因为欧拉回路或欧拉路在无向边中可以两个方向走 path初始为空
  int degree[MAX];
  memset(degree, 0, MAX * sizeof(int));
  // degree[i]指代节点i的度数
  for (int i = 0; i < g.g_cnt; ++i)
    for (int j = 0; j < g.g_cnt; ++j)
      degree[i] += g.g_m[i][j];
  if (loop_exist((int *)degree, g.g_cnt)) {
    //判断无向连通图G中是否存在欧拉回路
    dfs_loop(g, degree, 0, path);
    return (true);
  } else
    return (false);
}
bool loop_exist(int *degree, int n) { //判断无向连通图G中是否存在欧拉回路
  for (int i = 0; i < n; ++i)
    //若存在度数为奇数的节点则不存在欧拉回路
    if (degree[i] % 2 == 1)
      return (false);
  return (true);
}
void dfs_loop(graph_matrix g, int *degree, int beg,
              stack<int> &path) { //返回的path中从底至顶
                                  //逆序存储着欧拉回路的所有顶点下标号
                                  //对path出栈即可得到欧拉回路 path初始为空
  path.push(beg);
  //找出beg相邻节点中度数最大的节点 对他进行下一次dfs
  int d_max = max_degree(g, degree, beg);
  //终止递归条件 若beg没有邻节点则递归搜索结束
  if (d_max == -1)
    return;

  //每次从当前节点向外找一条新的边
  //并将当前走过的路删除
  g.g_m[beg][d_max] = 0;
  g.g_m[d_max][beg] = 0;
  //当前节点和下一个节点的度数也减1
  --degree[beg];
  --degree[d_max];
  dfs_loop(g, degree, d_max, path);
}
int max_degree(graph_matrix g, int *degree, int beg) {
  int d_max(0), index(-1);
  for (int i = 0; i < g.g_cnt; ++i) {
    if (i == beg)
      continue;
    //在beg相邻节点中找出最大度数节点
    if (g.g_m[beg][i] and d_max < degree[i])
      d_max = degree[i], index = i;
  }
  return (index);
}

<|endoftext|>


<commit_before>// stress inversion of matrices with varios methods
#include "Math/SMatrix.h"
#include "TMatrixTSym.h"
#include "TDecompChol.h"
#include "TDecompBK.h"

#include "TRandom.h"
#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include <limits>

#include "TStopwatch.h"

// matrix size
#ifndef N
#define N 5
#endif

bool doSelfTest = true;

//timer
namespace test {

#ifdef REPORT_TIME
   void reportTime( std::string s, double time);
#endif

   void printTime(TStopwatch & time, std::string s) {
      int pr = std::cout.precision(8);
      std::cout << s << "\t" << " time = " << time.RealTime() << "\t(sec)\t"
         //    << time.CpuTime()
                << std::endl;
      std::cout.precision(pr);
   }

   class Timer {

   public:

      Timer(const std::string & s = "") : fName(s), fTime(0)
      {
         fWatch.Start();
      }
      Timer(double & t, const std::string & s = "") : fName(s), fTime(&t)
      {
         fWatch.Start();
      }

      ~Timer() {
         fWatch.Stop();
         printTime(fWatch,fName);
#ifdef REPORT_TIME
         // report time
         reportTime(fName, fWatch.RealTime() );
#endif
         if (fTime) *fTime += fWatch.RealTime();
      }

   private:

      std::string fName;
      double * fTime;
      TStopwatch fWatch;

   };
}

using namespace ROOT::Math;

typedef  SMatrix<double,N,N, MatRepSym<double,N> >  SymMatrix;

// create matrix
template<class M>
M * createMatrix() {
   return new M();
}
// specialized for TMatrix
template<>
TMatrixTSym<double> * createMatrix<TMatrixTSym<double> >() {
   return new TMatrixTSym<double>(N);
}

//print matrix
template<class M>
void printMatrix(const M & m) {
   std::cout << m << std::endl;
}
template<>
void printMatrix<TMatrixTSym<double> >(const TMatrixTSym<double> & m ) {
   m.Print();
}

// generate matrices
template<class M>
void genMatrix(M  & m ) {
   TRandom & r = *gRandom;
   // generate first diagonal elemets
   for (int i = 0; i < N; ++i) {
      double maxVal = i*10000/(N-1) + 1;  // max condition is 10^4
      m(i,i) = r.Uniform(0, maxVal);
   }
   for (int i = 0; i < N; ++i) {
      for (int j = 0; j < i; ++j) {
         double v = 0.3*std::sqrt( m(i,i) * m(j,j) ); // this makes the matrix pos defined
         m(i,j) = r.Uniform(0, v);
         m(j,i) = m(i,j); // needed for TMatrix
      }
   }
}

// generate all matrices
template<class M>
void generate(std::vector<M*> & v) {
   int n = v.size();
   gRandom->SetSeed(111);
   for (int i = 0; i < n; ++i) {
      v[i] = createMatrix<M>();
      genMatrix(*v[i] );
   }
}

struct Choleski {};
struct BK {};
struct QR {};
struct Cramer {};
struct Default {};

template <class M, class Type>
struct TestInverter {
   static bool Inv ( const M & , M & ) { return false;}
   static bool Inv2 ( M & ) { return false;}
};

template <>
struct TestInverter<SymMatrix, Choleski> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.InverseChol(ifail);
      return  ifail == 0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.InvertChol();
   }
};

template <>
struct TestInverter<SymMatrix, BK> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.Inverse(ifail);
      return ifail==0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.Invert();
   }
};

template <>
struct TestInverter<SymMatrix, Cramer> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.InverseFast(ifail);
      return ifail==0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.InvertFast();
   }
};

#ifdef LATER
template <>
struct TestInverter<SymMatrix, QR> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      ROOT::Math::QRDecomposition<double> d;
      int ifail = 0;
      result = m.InverseFast(ifail);
      return ifail==0;
   }
};
#endif

//TMatrix functions

template <>
struct TestInverter<TMatrixDSym, Default> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      result = m;
      result.Invert();
      return true;
   }
   static bool Inv2 ( TMatrixDSym & m ) {
      m.Invert();
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, Cramer> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      result = m;
      result.InvertFast();
      return true;
   }
   static bool Inv2 ( TMatrixDSym & m ) {
      m.InvertFast();
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, Choleski> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      TDecompChol chol(m);
      if (!chol.Decompose() ) return false;
      chol.Invert(result);
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, BK> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      TDecompBK d(m);
      if (!d.Decompose() ) return false;
      d.Invert(result);
      return true;
   }
};

template<class M, class T>
double invert( const std::vector<M* >  & matlist, double & time,std::string s) {
   M result = *(matlist.front());
   test::Timer t(time,s);
   int nloop = matlist.size();
   double sum = 0;
   for (int l = 0; l < nloop; l++)
   {
      const M & m = *(matlist[l]);
      bool ok = TestInverter<M,T>::Inv(m,result);
      if (!ok) {
         std::cout << "inv failed for matrix " << l << std::endl;
         printMatrix<M>( m);
         return -1;
      }
      sum += result(0,1);
   }
   return sum;
}

// invert without copying the matrices (une INv2)

template<class M, class T>
double invert2( const std::vector<M* >  & matlist, double & time,std::string s) {

   // copy vector of matrices
   int nloop = matlist.size();
   std::vector<M *> vmat(nloop);
   for (int l = 0; l < nloop; l++)
   {
      vmat[l] = new M( *matlist[l] );
   }

   test::Timer t(time,s);
   double sum = 0;
   for (int l = 0; l < nloop; l++)
   {
      M & m = *(vmat[l]);
      bool ok = TestInverter<M,T>::Inv2(m);
      if (!ok) {
         std::cout << "inv failed for matrix " << l << std::endl;
         printMatrix<M>( m);
         return -1;
      }
      sum += m(0,1);
   }
   return sum;
}

bool equal(double d1, double d2, double stol = 10000) {
   std::cout.precision(12);  // tolerance is 1E-12
   double eps = stol * std::numeric_limits<double>::epsilon();
   if ( std::abs(d1) > 0 && std::abs(d2) > 0 )
      return  ( std::abs( d1-d2) < eps * std::max(std::abs(d1), std::abs(d2) ) );
   else if ( d1 == 0 )
      return std::abs(d2) < eps;
   else // d2 = 0
      return std::abs(d1) < eps;
}

// test matrices symmetric and positive defines
bool stressSymPosInversion(int n, bool selftest ) {

   // test smatrix

   std::vector<SymMatrix *> v1(n);
   generate(v1);
   std::vector<TMatrixDSym *> v2(n);
   generate(v2);

   bool iret = true;
   double time = 0;
   double s1 = invert<SymMatrix, Choleski> (v1, time,"SMatrix Chol");
   double s2 = invert<SymMatrix, BK> (v1, time,"SMatrix   BK");
   double s3 = invert<SymMatrix, Cramer> (v1, time,"SMatrix Cram");
   bool ok = ( equal(s1,s2) && equal(s1,s3) );
   if (!ok) {
      std::cout << "result SMatrix choleski  " << s1 << " BK   " << s2 << " cramer " << s3 << std::endl;
      std::cerr <<"Error:  inversion test for SMatrix FAILED ! " << std::endl;
   }
   iret  &= ok;
   std::cout << std::endl;

   double m1 = invert<TMatrixDSym, Choleski> (v2, time,"TMatrix Chol");
   double m2 = invert<TMatrixDSym, BK> (v2, time,"TMatrix   BK");
   double m3 = invert<TMatrixDSym, Cramer> (v2, time,"TMatrix Cram");
   double m4 = invert<TMatrixDSym, Default> (v2, time,"TMatrix  Def");

   ok =  ( equal(m1,m2) && equal(m1,m3) && equal(m1,m4) );
   if (!ok) {
      std::cout << "result TMatrix choleski  " << m1 << " BK   " << m2
                << " cramer " << m3 << " default " << m4 << std::endl;
      std::cerr <<"Error:  inversion test for TMatrix FAILED ! " << std::endl;
   }
   iret  &= ok;
   std::cout << std::endl;

      // test using self inversion
   if (selftest) {
      std::cout << "\n - self inversion test \n";
      double s11 = invert2<SymMatrix, Choleski> (v1, time,"SMatrix Chol");
      double s12 = invert2<SymMatrix, BK> (v1, time,"SMatrix   BK");
      double s13 = invert2<SymMatrix, Cramer> (v1, time,"SMatrix Cram");
      ok =  ( equal(s11,s12) && equal(s11,s13) );
      if (!ok) {
         std::cout << "result SMatrix choleski  " << s11 << " BK   " << s12 << " cramer " << s13 << std::endl;
         std::cerr <<"Error:  self inversion test for SMatrix FAILED ! " << std::endl;
      }
      iret  &= ok;
      std::cout << std::endl;

      double m13 = invert2<TMatrixDSym, Cramer> (v2, time,"TMatrix Cram");
      double m14 = invert2<TMatrixDSym, Default> (v2, time,"TMatrix  Def");
      ok =  ( equal(m13,m14)  );
      if (!ok) {
         std::cout << "result TMatrix  cramer " << m13 << " default " << m14 << std::endl;
         std::cerr <<"Error:  self inversion test for TMatrix FAILED ! " << std::endl;
      }
      iret  &= ok;
      std::cout << std::endl;
   }

   return iret;
}

int testInversion(int n = 100000) {
   std::cout << "Test Inversion for matrix with N = " << N << std::endl;
   bool ok = stressSymPosInversion(n, doSelfTest);
   std::cerr << "Test inversion of positive defined matrix ....... ";
   if (ok) std::cerr << "OK \n";
   else std::cerr << "FAILED \n";
   return (ok) ? 0 : -1;
}

int main() {
   return testInversion();
}
<commit_msg>[math] Replace preprocessor define with constexpr in testInversion.cxx<commit_after>// stress inversion of matrices with varios methods
#include "Math/SMatrix.h"
#include "TMatrixTSym.h"
#include "TDecompChol.h"
#include "TDecompBK.h"

#include "TRandom.h"
#include <vector>
#include <string>
#include <iostream>
#include <cmath>
#include <limits>

#include "TStopwatch.h"

// matrix size
constexpr unsigned int N = 5;

bool doSelfTest = true;

//timer
namespace test {

#ifdef REPORT_TIME
   void reportTime( std::string s, double time);
#endif

   void printTime(TStopwatch & time, std::string s) {
      int pr = std::cout.precision(8);
      std::cout << s << "\t" << " time = " << time.RealTime() << "\t(sec)\t"
         //    << time.CpuTime()
                << std::endl;
      std::cout.precision(pr);
   }

   class Timer {

   public:

      Timer(const std::string & s = "") : fName(s), fTime(0)
      {
         fWatch.Start();
      }
      Timer(double & t, const std::string & s = "") : fName(s), fTime(&t)
      {
         fWatch.Start();
      }

      ~Timer() {
         fWatch.Stop();
         printTime(fWatch,fName);
#ifdef REPORT_TIME
         // report time
         reportTime(fName, fWatch.RealTime() );
#endif
         if (fTime) *fTime += fWatch.RealTime();
      }

   private:

      std::string fName;
      double * fTime;
      TStopwatch fWatch;

   };
}

using namespace ROOT::Math;

typedef  SMatrix<double,N,N, MatRepSym<double,N> >  SymMatrix;

// create matrix
template<class M>
M * createMatrix() {
   return new M();
}
// specialized for TMatrix
template<>
TMatrixTSym<double> * createMatrix<TMatrixTSym<double> >() {
   return new TMatrixTSym<double>(N);
}

//print matrix
template<class M>
void printMatrix(const M & m) {
   std::cout << m << std::endl;
}
template<>
void printMatrix<TMatrixTSym<double> >(const TMatrixTSym<double> & m ) {
   m.Print();
}

// generate matrices
template<class M>
void genMatrix(M  & m ) {
   TRandom & r = *gRandom;
   // generate first diagonal elemets
   for (int i = 0; i < N; ++i) {
      double maxVal = i*10000/(N-1) + 1;  // max condition is 10^4
      m(i,i) = r.Uniform(0, maxVal);
   }
   for (int i = 0; i < N; ++i) {
      for (int j = 0; j < i; ++j) {
         double v = 0.3*std::sqrt( m(i,i) * m(j,j) ); // this makes the matrix pos defined
         m(i,j) = r.Uniform(0, v);
         m(j,i) = m(i,j); // needed for TMatrix
      }
   }
}

// generate all matrices
template<class M>
void generate(std::vector<M*> & v) {
   int n = v.size();
   gRandom->SetSeed(111);
   for (int i = 0; i < n; ++i) {
      v[i] = createMatrix<M>();
      genMatrix(*v[i] );
   }
}

struct Choleski {};
struct BK {};
struct QR {};
struct Cramer {};
struct Default {};

template <class M, class Type>
struct TestInverter {
   static bool Inv ( const M & , M & ) { return false;}
   static bool Inv2 ( M & ) { return false;}
};

template <>
struct TestInverter<SymMatrix, Choleski> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.InverseChol(ifail);
      return  ifail == 0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.InvertChol();
   }
};

template <>
struct TestInverter<SymMatrix, BK> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.Inverse(ifail);
      return ifail==0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.Invert();
   }
};

template <>
struct TestInverter<SymMatrix, Cramer> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      int ifail = 0;
      result = m.InverseFast(ifail);
      return ifail==0;
   }
   static bool Inv2 ( SymMatrix & m ) {
      return m.InvertFast();
   }
};

#ifdef LATER
template <>
struct TestInverter<SymMatrix, QR> {
   static bool Inv ( const SymMatrix & m, SymMatrix & result ) {
      ROOT::Math::QRDecomposition<double> d;
      int ifail = 0;
      result = m.InverseFast(ifail);
      return ifail==0;
   }
};
#endif

//TMatrix functions

template <>
struct TestInverter<TMatrixDSym, Default> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      result = m;
      result.Invert();
      return true;
   }
   static bool Inv2 ( TMatrixDSym & m ) {
      m.Invert();
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, Cramer> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      result = m;
      result.InvertFast();
      return true;
   }
   static bool Inv2 ( TMatrixDSym & m ) {
      m.InvertFast();
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, Choleski> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      TDecompChol chol(m);
      if (!chol.Decompose() ) return false;
      chol.Invert(result);
      return true;
   }
};

template <>
struct TestInverter<TMatrixDSym, BK> {
   static bool Inv ( const TMatrixDSym & m, TMatrixDSym & result ) {
      TDecompBK d(m);
      if (!d.Decompose() ) return false;
      d.Invert(result);
      return true;
   }
};

template<class M, class T>
double invert( const std::vector<M* >  & matlist, double & time,std::string s) {
   M result = *(matlist.front());
   test::Timer t(time,s);
   int nloop = matlist.size();
   double sum = 0;
   for (int l = 0; l < nloop; l++)
   {
      const M & m = *(matlist[l]);
      bool ok = TestInverter<M,T>::Inv(m,result);
      if (!ok) {
         std::cout << "inv failed for matrix " << l << std::endl;
         printMatrix<M>( m);
         return -1;
      }
      sum += result(0,1);
   }
   return sum;
}

// invert without copying the matrices (une INv2)

template<class M, class T>
double invert2( const std::vector<M* >  & matlist, double & time,std::string s) {

   // copy vector of matrices
   int nloop = matlist.size();
   std::vector<M *> vmat(nloop);
   for (int l = 0; l < nloop; l++)
   {
      vmat[l] = new M( *matlist[l] );
   }

   test::Timer t(time,s);
   double sum = 0;
   for (int l = 0; l < nloop; l++)
   {
      M & m = *(vmat[l]);
      bool ok = TestInverter<M,T>::Inv2(m);
      if (!ok) {
         std::cout << "inv failed for matrix " << l << std::endl;
         printMatrix<M>( m);
         return -1;
      }
      sum += m(0,1);
   }
   return sum;
}

bool equal(double d1, double d2, double stol = 10000) {
   std::cout.precision(12);  // tolerance is 1E-12
   double eps = stol * std::numeric_limits<double>::epsilon();
   if ( std::abs(d1) > 0 && std::abs(d2) > 0 )
      return  ( std::abs( d1-d2) < eps * std::max(std::abs(d1), std::abs(d2) ) );
   else if ( d1 == 0 )
      return std::abs(d2) < eps;
   else // d2 = 0
      return std::abs(d1) < eps;
}

// test matrices symmetric and positive defines
bool stressSymPosInversion(int n, bool selftest ) {

   // test smatrix

   std::vector<SymMatrix *> v1(n);
   generate(v1);
   std::vector<TMatrixDSym *> v2(n);
   generate(v2);

   bool iret = true;
   double time = 0;
   double s1 = invert<SymMatrix, Choleski> (v1, time,"SMatrix Chol");
   double s2 = invert<SymMatrix, BK> (v1, time,"SMatrix   BK");
   double s3 = invert<SymMatrix, Cramer> (v1, time,"SMatrix Cram");
   bool ok = ( equal(s1,s2) && equal(s1,s3) );
   if (!ok) {
      std::cout << "result SMatrix choleski  " << s1 << " BK   " << s2 << " cramer " << s3 << std::endl;
      std::cerr <<"Error:  inversion test for SMatrix FAILED ! " << std::endl;
   }
   iret  &= ok;
   std::cout << std::endl;

   double m1 = invert<TMatrixDSym, Choleski> (v2, time,"TMatrix Chol");
   double m2 = invert<TMatrixDSym, BK> (v2, time,"TMatrix   BK");
   double m3 = invert<TMatrixDSym, Cramer> (v2, time,"TMatrix Cram");
   double m4 = invert<TMatrixDSym, Default> (v2, time,"TMatrix  Def");

   ok =  ( equal(m1,m2) && equal(m1,m3) && equal(m1,m4) );
   if (!ok) {
      std::cout << "result TMatrix choleski  " << m1 << " BK   " << m2
                << " cramer " << m3 << " default " << m4 << std::endl;
      std::cerr <<"Error:  inversion test for TMatrix FAILED ! " << std::endl;
   }
   iret  &= ok;
   std::cout << std::endl;

      // test using self inversion
   if (selftest) {
      std::cout << "\n - self inversion test \n";
      double s11 = invert2<SymMatrix, Choleski> (v1, time,"SMatrix Chol");
      double s12 = invert2<SymMatrix, BK> (v1, time,"SMatrix   BK");
      double s13 = invert2<SymMatrix, Cramer> (v1, time,"SMatrix Cram");
      ok =  ( equal(s11,s12) && equal(s11,s13) );
      if (!ok) {
         std::cout << "result SMatrix choleski  " << s11 << " BK   " << s12 << " cramer " << s13 << std::endl;
         std::cerr <<"Error:  self inversion test for SMatrix FAILED ! " << std::endl;
      }
      iret  &= ok;
      std::cout << std::endl;

      double m13 = invert2<TMatrixDSym, Cramer> (v2, time,"TMatrix Cram");
      double m14 = invert2<TMatrixDSym, Default> (v2, time,"TMatrix  Def");
      ok =  ( equal(m13,m14)  );
      if (!ok) {
         std::cout << "result TMatrix  cramer " << m13 << " default " << m14 << std::endl;
         std::cerr <<"Error:  self inversion test for TMatrix FAILED ! " << std::endl;
      }
      iret  &= ok;
      std::cout << std::endl;
   }

   return iret;
}

int testInversion(int n = 100000) {
   std::cout << "Test Inversion for matrix with N = " << N << std::endl;
   bool ok = stressSymPosInversion(n, doSelfTest);
   std::cerr << "Test inversion of positive defined matrix ....... ";
   if (ok) std::cerr << "OK \n";
   else std::cerr << "FAILED \n";
   return (ok) ? 0 : -1;
}

int main() {
   return testInversion();
}
<|endoftext|>