<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2017 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "depthaov.h"

// appleseed.renderer headers.
#include "renderer/kernel/aov/aovaccumulator.h"
#include "renderer/kernel/shading/shadingpoint.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/aov/aov.h"

// appleseed.foundation headers.
#include "foundation/utility/api/apistring.h"
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <limits>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Depth AOV accumulator.
    //

    class DepthAOVAccumulator
      : public AOVAccumulator
    {
      public:
        explicit DepthAOVAccumulator(const size_t index)
          : AOVAccumulator(index)
        {
        }

        virtual void reset() APPLESEED_OVERRIDE
        {
            m_depth = numeric_limits<float>::max();
        }

        virtual void write(
            const ShadingPoint&     shading_point,
            const Camera&           camera) APPLESEED_OVERRIDE
        {
            if (shading_point.hit())
                m_depth = shading_point.get_distance();
        }

        virtual void flush(ShadingResult& result) APPLESEED_OVERRIDE
        {
            result.m_aovs[m_index].m_color.set(m_depth);
            result.m_aovs[m_index].m_alpha.set(1.0f);
        }

        float m_depth;
    };

    //
    // Depth AOV.
    //

    const char* Model = "depth_aov";

    class DepthAOV
      : public AOV
    {
      public:
        DepthAOV(const char* name, const ParamArray& params)
          : AOV(name, params)
        {
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual size_t get_channel_count() const APPLESEED_OVERRIDE
        {
            return 1;
        }

        virtual const char* get_channel_name(const size_t i) const APPLESEED_OVERRIDE
        {
            return "Z";
        }

        virtual bool has_color_data() const APPLESEED_OVERRIDE
        {
            return false;
        }

        virtual auto_release_ptr<AOVAccumulator> create_accumulator(
            const size_t index) const APPLESEED_OVERRIDE
        {
            return auto_release_ptr<AOVAccumulator>(new DepthAOVAccumulator(index));
        }
    };
}

//
// DepthAOVFactory class implementation.
//

const char* DepthAOVFactory::get_model() const
{
    return Model;
}

Dictionary DepthAOVFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", Model)
            .insert("label", "Depth")
            .insert("default_model", "true");
}

DictionaryArray DepthAOVFactory::get_input_metadata() const
{
    DictionaryArray metadata;
    return metadata;
}

auto_release_ptr<AOV> DepthAOVFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<AOV>(
            new DepthAOV(name, params));
}

auto_release_ptr<AOV> DepthAOVFactory::static_create(
    const char*         name,
    const ParamArray&   params)
{
    return
        auto_release_ptr<AOV>(
            new DepthAOV(name, params));
}

}   // namespace renderer
<commit_msg>Fix compilation on Windows<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2017 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "depthaov.h"

// appleseed.renderer headers.
#include "renderer/kernel/aov/aovaccumulator.h"
#include "renderer/kernel/shading/shadingpoint.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/aov/aov.h"

// appleseed.foundation headers.
#include "foundation/utility/api/apistring.h"
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <limits>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Depth AOV accumulator.
    //

    class DepthAOVAccumulator
      : public AOVAccumulator
    {
      public:
        explicit DepthAOVAccumulator(const size_t index)
          : AOVAccumulator(index)
        {
        }

        virtual void reset() APPLESEED_OVERRIDE
        {
            m_depth = numeric_limits<float>::max();
        }

        virtual void write(
            const ShadingPoint&     shading_point,
            const Camera&           camera) APPLESEED_OVERRIDE
        {
            if (shading_point.hit())
                m_depth = static_cast<float>(shading_point.get_distance());
        }

        virtual void flush(ShadingResult& result) APPLESEED_OVERRIDE
        {
            result.m_aovs[m_index].m_color.set(m_depth);
            result.m_aovs[m_index].m_alpha.set(1.0f);
        }

        float m_depth;
    };

    //
    // Depth AOV.
    //

    const char* Model = "depth_aov";

    class DepthAOV
      : public AOV
    {
      public:
        DepthAOV(const char* name, const ParamArray& params)
          : AOV(name, params)
        {
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual size_t get_channel_count() const APPLESEED_OVERRIDE
        {
            return 1;
        }

        virtual const char* get_channel_name(const size_t i) const APPLESEED_OVERRIDE
        {
            return "Z";
        }

        virtual bool has_color_data() const APPLESEED_OVERRIDE
        {
            return false;
        }

        virtual auto_release_ptr<AOVAccumulator> create_accumulator(
            const size_t index) const APPLESEED_OVERRIDE
        {
            return auto_release_ptr<AOVAccumulator>(new DepthAOVAccumulator(index));
        }
    };
}

//
// DepthAOVFactory class implementation.
//

const char* DepthAOVFactory::get_model() const
{
    return Model;
}

Dictionary DepthAOVFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", Model)
            .insert("label", "Depth")
            .insert("default_model", "true");
}

DictionaryArray DepthAOVFactory::get_input_metadata() const
{
    DictionaryArray metadata;
    return metadata;
}

auto_release_ptr<AOV> DepthAOVFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<AOV>(
            new DepthAOV(name, params));
}

auto_release_ptr<AOV> DepthAOVFactory::static_create(
    const char*         name,
    const ParamArray&   params)
{
    return
        auto_release_ptr<AOV>(
            new DepthAOV(name, params));
}

}   // namespace renderer
<|endoftext|>


<commit_before>/*
 * BoundingBoxRenderer.cpp
 *
 * Copyright (C) 2019 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 */
#include "stdafx.h"
#include "mmcore/nextgen/BoundingBoxRenderer.h"

#include "mmcore/CoreInstance.h"
#include "mmcore/param/BoolParam.h"
#include "mmcore/param/ColorParam.h"
#include "vislib/graphics/gl/ShaderSource.h"
#include "vislib/sys/Log.h"

using namespace megamol::core;
using namespace megamol::core::nextgen;
using namespace megamol::core::view;

/*
 * BoundingBoxRenderer::BoundingBoxRenderer
 */
BoundingBoxRenderer::BoundingBoxRenderer(void)
    : RendererModule<CallRender3D_2>()
    , enableBoundingBoxSlot("enableBoundingBox", "Enables the rendering of the bounding box")
    , boundingBoxColorSlot("boundingBoxColor", "Color of the bounding box")
    , smoothLineSlot("smoothLines", "Enables the smoothing of lines (may look strange on some setups)")
    , enableViewCubeSlot("enableViewCube", "Enables the rendering of the view cube")
    , vbo(0)
    , ibo(0)
    , va(0) {

    this->enableBoundingBoxSlot.SetParameter(new param::BoolParam(true));
    this->MakeSlotAvailable(&this->enableBoundingBoxSlot);

    this->boundingBoxColorSlot.SetParameter(new param::ColorParam("#ffffffff"));
    this->MakeSlotAvailable(&this->boundingBoxColorSlot);

    this->smoothLineSlot.SetParameter(new param::BoolParam(true));
    this->MakeSlotAvailable(&this->smoothLineSlot);

    this->enableViewCubeSlot.SetParameter(new param::BoolParam(false));
    this->MakeSlotAvailable(&this->enableViewCubeSlot);

    this->MakeSlotAvailable(&this->chainRenderSlot);
    this->MakeSlotAvailable(&this->renderSlot);
}

/*
 * BoundingBoxRenderer::~BoundingBoxRenderer
 */
BoundingBoxRenderer::~BoundingBoxRenderer(void) { this->Release(); }

/*
 * BoundingBoxRenderer::create
 */
bool BoundingBoxRenderer::create(void) {
    // TODO the vislib shaders have to die a slow and painful death
    vislib::graphics::gl::ShaderSource bbVertSrc;
    vislib::graphics::gl::ShaderSource bbFragSrc;
    if (!this->GetCoreInstance()->ShaderSourceFactory().MakeShaderSource("boundingbox::vertex", bbVertSrc)) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to load vertex shader source for bounding box line shader");
    }
    if (!this->GetCoreInstance()->ShaderSourceFactory().MakeShaderSource("boundingbox::fragment", bbFragSrc)) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to load fragment shader source for bounding box line shader");
    }
    try {
        if (!this->lineShader.Create(bbVertSrc.Code(), bbVertSrc.Count(), bbFragSrc.Code(), bbFragSrc.Count())) {
            throw vislib::Exception("Shader creation failure", __FILE__, __LINE__);
        }
    } catch (vislib::Exception e) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to create bounding box line shader: %s\n", e.GetMsgA());
        return false;
    }

    // the used vertex order resembles the one used in the old View3D
    std::vector<float> vertexCoords = {-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
    std::vector<unsigned int> vertexIndices = {0, 2, 3, 1, 4, 5, 7, 6, 2, 6, 7, 3, 0, 1, 5, 4, 0, 4, 6, 2, 1, 3, 7, 5};

    glCreateBuffers(1, &this->vbo);
    glCreateBuffers(1, &this->ibo);
    glCreateVertexArrays(1, &this->va);

    glBindVertexArray(this->va);
    glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ibo);

    glEnableVertexAttribArray(0);

    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexCoords.size(), vertexCoords.data(), GL_STATIC_DRAW);
    glBufferData(
        GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * vertexIndices.size(), vertexIndices.data(), GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);

    glBindVertexArray(0);

    return true;
}

/*
 * BoundingBoxRenderer::release
 */
void BoundingBoxRenderer::release(void) {
    this->lineShader.Release();
    if (this->va != 0) {
        glDeleteVertexArrays(1, &this->va);
        this->va = 0;
    }
    if (this->vbo != 0) {
        glDeleteBuffers(1, &this->vbo);
        this->vbo = 0;
    }
    if (this->ibo != 0) {
        glDeleteBuffers(1, &this->ibo);
        this->ibo = 0;
    }
}

/*
 * BoundingBoxRenderer::GetExtents
 */
bool BoundingBoxRenderer::GetExtents(CallRender3D_2& call) {
    CallRender3D_2* chainedCall = this->chainRenderSlot.CallAs<CallRender3D_2>();
    if (chainedCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteError(
            "The BoundingBoxRenderer does not work without a renderer attached to its right");
        return false;
    }
    *chainedCall = call;
    bool retVal = (*chainedCall)(view::AbstractCallRender::FnGetExtents);
    call = *chainedCall;
    return retVal;
}

/*
 * BoundingBoxRenderer::Render
 */
bool BoundingBoxRenderer::Render(CallRender3D_2& call) {
    auto leftSlotParent = call.PeekCallerSlot()->Parent();
    std::shared_ptr<const view::AbstractView> viewptr =
        std::dynamic_pointer_cast<const view::AbstractView>(leftSlotParent);

    if (viewptr != nullptr) {
        // TODO move this behind the fbo magic?
        auto vp = call.GetViewport();
        glViewport(vp.Left(), vp.Bottom(), vp.Width(), vp.Height());
        auto backCol = call.BackgroundColor();
        glClearColor(backCol.x, backCol.y, backCol.z, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    CallRender3D_2* chainedCall = this->chainRenderSlot.CallAs<CallRender3D_2>();
    if (chainedCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteError(
            "The BoundingBoxRenderer does not work without a renderer attached to its right");
        return false;
    }

    Camera_2 cam;
    call.GetCamera(cam);

    cam_type::snapshot_type snapshot;
    cam_type::matrix_type viewT, projT;

    cam.calc_matrices(snapshot, viewT, projT);

    glm::mat4 view = viewT;
    glm::mat4 proj = projT;
    glm::mat4 mvp = proj * view;

    auto boundingBoxes = chainedCall->AccessBoundingBoxes();
    auto smoothLines = this->smoothLineSlot.Param<param::BoolParam>()->Value();

    bool renderRes = true;
    if (this->enableBoundingBoxSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderBoundingBoxBack(mvp, boundingBoxes, smoothLines);
    }
    renderRes &= (*chainedCall)(view::AbstractCallRender::FnRender);
    if (this->enableBoundingBoxSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderBoundingBoxFront(mvp, boundingBoxes, smoothLines);
    }
    if (this->enableViewCubeSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderViewCube(call);
    }

    return renderRes;
}

/*
 * BoundingBoxRenderer::RenderBoundingBoxFront
 */
bool BoundingBoxRenderer::RenderBoundingBoxFront(const glm::mat4& mvp, const BoundingBoxes_2& bb, bool smoothLines) {
    glm::vec3 bbmin = glm::vec3(bb.BoundingBox().Left(), bb.BoundingBox().Bottom(), bb.BoundingBox().Back());
    glm::vec3 bbmax = glm::vec3(bb.BoundingBox().Right(), bb.BoundingBox().Top(), bb.BoundingBox().Front());

    auto colptr = this->boundingBoxColorSlot.Param<param::ColorParam>()->Value();

    this->lineShader.Enable();

    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    if (smoothLines) glEnable(GL_LINE_SMOOTH);
    glLineWidth(1.75f);
    glPolygonMode(GL_FRONT, GL_LINE);

    glBindVertexArray(this->va);
    glEnableVertexAttribArray(0);

    glUniformMatrix4fv(this->lineShader.ParameterLocation("mvp"), 1, GL_FALSE, glm::value_ptr(mvp));
    glUniform3fv(this->lineShader.ParameterLocation("bbMin"), 1, glm::value_ptr(bbmin));
    glUniform3fv(this->lineShader.ParameterLocation("bbMax"), 1, glm::value_ptr(bbmax));
    glUniform3f(this->lineShader.ParameterLocation("color"), colptr[0], colptr[1], colptr[2]);

    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);

    glEnable(GL_LIGHTING);
    glDisable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    if (smoothLines) glDisable(GL_LINE_SMOOTH);
    glLineWidth(1.0f);
    glDisable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT, GL_FILL);

    this->lineShader.Disable();

    return true;
}

/*
 * BoundingBoxRenderer::RenderBoundingBoxBack
 */
bool BoundingBoxRenderer::RenderBoundingBoxBack(const glm::mat4& mvp, const BoundingBoxes_2& bb, bool smoothLines) {
    glm::vec3 bbmin = glm::vec3(bb.BoundingBox().Left(), bb.BoundingBox().Bottom(), bb.BoundingBox().Back());
    glm::vec3 bbmax = glm::vec3(bb.BoundingBox().Right(), bb.BoundingBox().Top(), bb.BoundingBox().Front());

    auto color = this->boundingBoxColorSlot.Param<param::ColorParam>()->Value();

    this->lineShader.Enable();

    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    if (smoothLines) glEnable(GL_LINE_SMOOTH);
    glLineWidth(1.25f);
    glPolygonMode(GL_BACK, GL_LINE);

    glBindVertexArray(this->va);
    glEnableVertexAttribArray(0);

    glUniformMatrix4fv(this->lineShader.ParameterLocation("mvp"), 1, GL_FALSE, glm::value_ptr(mvp));
    glUniform3fv(this->lineShader.ParameterLocation("bbMin"), 1, glm::value_ptr(bbmin));
    glUniform3fv(this->lineShader.ParameterLocation("bbMax"), 1, glm::value_ptr(bbmax));
    glUniform3f(this->lineShader.ParameterLocation("color"), color[0], color[1], color[2]);

    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);

    glEnable(GL_LIGHTING);
    glDisable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    if (smoothLines) glDisable(GL_LINE_SMOOTH);
    glLineWidth(1.0f);
    glDisable(GL_CULL_FACE);
    glPolygonMode(GL_BACK, GL_FILL);

    this->lineShader.Disable();

    return true;
}

/*
 * BoundingBoxRenderer::RenderViewCube
 */
bool BoundingBoxRenderer::RenderViewCube(CallRender3D_2& call) { return true; }
<commit_msg>namespace fix bbox renderer<commit_after>/*
 * BoundingBoxRenderer.cpp
 *
 * Copyright (C) 2019 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 */
#include "stdafx.h"
#include "mmcore/view/BoundingBoxRenderer.h"

#include "mmcore/CoreInstance.h"
#include "mmcore/param/BoolParam.h"
#include "mmcore/param/ColorParam.h"
#include "vislib/graphics/gl/ShaderSource.h"
#include "vislib/sys/Log.h"

using namespace megamol::core;
using namespace megamol::core::view;

/*
 * BoundingBoxRenderer::BoundingBoxRenderer
 */
BoundingBoxRenderer::BoundingBoxRenderer(void)
    : RendererModule<CallRender3D_2>()
    , enableBoundingBoxSlot("enableBoundingBox", "Enables the rendering of the bounding box")
    , boundingBoxColorSlot("boundingBoxColor", "Color of the bounding box")
    , smoothLineSlot("smoothLines", "Enables the smoothing of lines (may look strange on some setups)")
    , enableViewCubeSlot("enableViewCube", "Enables the rendering of the view cube")
    , vbo(0)
    , ibo(0)
    , va(0) {

    this->enableBoundingBoxSlot.SetParameter(new param::BoolParam(true));
    this->MakeSlotAvailable(&this->enableBoundingBoxSlot);

    this->boundingBoxColorSlot.SetParameter(new param::ColorParam("#ffffffff"));
    this->MakeSlotAvailable(&this->boundingBoxColorSlot);

    this->smoothLineSlot.SetParameter(new param::BoolParam(true));
    this->MakeSlotAvailable(&this->smoothLineSlot);

    this->enableViewCubeSlot.SetParameter(new param::BoolParam(false));
    this->MakeSlotAvailable(&this->enableViewCubeSlot);

    this->MakeSlotAvailable(&this->chainRenderSlot);
    this->MakeSlotAvailable(&this->renderSlot);
}

/*
 * BoundingBoxRenderer::~BoundingBoxRenderer
 */
BoundingBoxRenderer::~BoundingBoxRenderer(void) { this->Release(); }

/*
 * BoundingBoxRenderer::create
 */
bool BoundingBoxRenderer::create(void) {
    // TODO the vislib shaders have to die a slow and painful death
    vislib::graphics::gl::ShaderSource bbVertSrc;
    vislib::graphics::gl::ShaderSource bbFragSrc;
    if (!this->GetCoreInstance()->ShaderSourceFactory().MakeShaderSource("boundingbox::vertex", bbVertSrc)) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to load vertex shader source for bounding box line shader");
    }
    if (!this->GetCoreInstance()->ShaderSourceFactory().MakeShaderSource("boundingbox::fragment", bbFragSrc)) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to load fragment shader source for bounding box line shader");
    }
    try {
        if (!this->lineShader.Create(bbVertSrc.Code(), bbVertSrc.Count(), bbFragSrc.Code(), bbFragSrc.Count())) {
            throw vislib::Exception("Shader creation failure", __FILE__, __LINE__);
        }
    } catch (vislib::Exception e) {
        vislib::sys::Log::DefaultLog.WriteError("Unable to create bounding box line shader: %s\n", e.GetMsgA());
        return false;
    }

    // the used vertex order resembles the one used in the old View3D
    std::vector<float> vertexCoords = {-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
        -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
    std::vector<unsigned int> vertexIndices = {0, 2, 3, 1, 4, 5, 7, 6, 2, 6, 7, 3, 0, 1, 5, 4, 0, 4, 6, 2, 1, 3, 7, 5};

    glCreateBuffers(1, &this->vbo);
    glCreateBuffers(1, &this->ibo);
    glCreateVertexArrays(1, &this->va);

    glBindVertexArray(this->va);
    glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ibo);

    glEnableVertexAttribArray(0);

    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexCoords.size(), vertexCoords.data(), GL_STATIC_DRAW);
    glBufferData(
        GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * vertexIndices.size(), vertexIndices.data(), GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);

    glBindVertexArray(0);

    return true;
}

/*
 * BoundingBoxRenderer::release
 */
void BoundingBoxRenderer::release(void) {
    this->lineShader.Release();
    if (this->va != 0) {
        glDeleteVertexArrays(1, &this->va);
        this->va = 0;
    }
    if (this->vbo != 0) {
        glDeleteBuffers(1, &this->vbo);
        this->vbo = 0;
    }
    if (this->ibo != 0) {
        glDeleteBuffers(1, &this->ibo);
        this->ibo = 0;
    }
}

/*
 * BoundingBoxRenderer::GetExtents
 */
bool BoundingBoxRenderer::GetExtents(CallRender3D_2& call) {
    CallRender3D_2* chainedCall = this->chainRenderSlot.CallAs<CallRender3D_2>();
    if (chainedCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteError(
            "The BoundingBoxRenderer does not work without a renderer attached to its right");
        return false;
    }
    *chainedCall = call;
    bool retVal = (*chainedCall)(view::AbstractCallRender::FnGetExtents);
    call = *chainedCall;
    return retVal;
}

/*
 * BoundingBoxRenderer::Render
 */
bool BoundingBoxRenderer::Render(CallRender3D_2& call) {
    auto leftSlotParent = call.PeekCallerSlot()->Parent();
    std::shared_ptr<const view::AbstractView> viewptr =
        std::dynamic_pointer_cast<const view::AbstractView>(leftSlotParent);

    if (viewptr != nullptr) {
        // TODO move this behind the fbo magic?
        auto vp = call.GetViewport();
        glViewport(vp.Left(), vp.Bottom(), vp.Width(), vp.Height());
        auto backCol = call.BackgroundColor();
        glClearColor(backCol.x, backCol.y, backCol.z, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    CallRender3D_2* chainedCall = this->chainRenderSlot.CallAs<CallRender3D_2>();
    if (chainedCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteError(
            "The BoundingBoxRenderer does not work without a renderer attached to its right");
        return false;
    }

    Camera_2 cam;
    call.GetCamera(cam);

    cam_type::snapshot_type snapshot;
    cam_type::matrix_type viewT, projT;

    cam.calc_matrices(snapshot, viewT, projT);

    glm::mat4 view = viewT;
    glm::mat4 proj = projT;
    glm::mat4 mvp = proj * view;

    auto boundingBoxes = chainedCall->AccessBoundingBoxes();
    auto smoothLines = this->smoothLineSlot.Param<param::BoolParam>()->Value();

    bool renderRes = true;
    if (this->enableBoundingBoxSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderBoundingBoxBack(mvp, boundingBoxes, smoothLines);
    }
    renderRes &= (*chainedCall)(view::AbstractCallRender::FnRender);
    if (this->enableBoundingBoxSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderBoundingBoxFront(mvp, boundingBoxes, smoothLines);
    }
    if (this->enableViewCubeSlot.Param<param::BoolParam>()->Value()) {
        renderRes &= this->RenderViewCube(call);
    }

    return renderRes;
}

/*
 * BoundingBoxRenderer::RenderBoundingBoxFront
 */
bool BoundingBoxRenderer::RenderBoundingBoxFront(const glm::mat4& mvp, const BoundingBoxes_2& bb, bool smoothLines) {
    glm::vec3 bbmin = glm::vec3(bb.BoundingBox().Left(), bb.BoundingBox().Bottom(), bb.BoundingBox().Back());
    glm::vec3 bbmax = glm::vec3(bb.BoundingBox().Right(), bb.BoundingBox().Top(), bb.BoundingBox().Front());

    auto colptr = this->boundingBoxColorSlot.Param<param::ColorParam>()->Value();

    this->lineShader.Enable();

    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    if (smoothLines) glEnable(GL_LINE_SMOOTH);
    glLineWidth(1.75f);
    glPolygonMode(GL_FRONT, GL_LINE);

    glBindVertexArray(this->va);
    glEnableVertexAttribArray(0);

    glUniformMatrix4fv(this->lineShader.ParameterLocation("mvp"), 1, GL_FALSE, glm::value_ptr(mvp));
    glUniform3fv(this->lineShader.ParameterLocation("bbMin"), 1, glm::value_ptr(bbmin));
    glUniform3fv(this->lineShader.ParameterLocation("bbMax"), 1, glm::value_ptr(bbmax));
    glUniform3f(this->lineShader.ParameterLocation("color"), colptr[0], colptr[1], colptr[2]);

    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);

    glEnable(GL_LIGHTING);
    glDisable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    if (smoothLines) glDisable(GL_LINE_SMOOTH);
    glLineWidth(1.0f);
    glDisable(GL_CULL_FACE);
    glPolygonMode(GL_FRONT, GL_FILL);

    this->lineShader.Disable();

    return true;
}

/*
 * BoundingBoxRenderer::RenderBoundingBoxBack
 */
bool BoundingBoxRenderer::RenderBoundingBoxBack(const glm::mat4& mvp, const BoundingBoxes_2& bb, bool smoothLines) {
    glm::vec3 bbmin = glm::vec3(bb.BoundingBox().Left(), bb.BoundingBox().Bottom(), bb.BoundingBox().Back());
    glm::vec3 bbmax = glm::vec3(bb.BoundingBox().Right(), bb.BoundingBox().Top(), bb.BoundingBox().Front());

    auto color = this->boundingBoxColorSlot.Param<param::ColorParam>()->Value();

    this->lineShader.Enable();

    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    if (smoothLines) glEnable(GL_LINE_SMOOTH);
    glLineWidth(1.25f);
    glPolygonMode(GL_BACK, GL_LINE);

    glBindVertexArray(this->va);
    glEnableVertexAttribArray(0);

    glUniformMatrix4fv(this->lineShader.ParameterLocation("mvp"), 1, GL_FALSE, glm::value_ptr(mvp));
    glUniform3fv(this->lineShader.ParameterLocation("bbMin"), 1, glm::value_ptr(bbmin));
    glUniform3fv(this->lineShader.ParameterLocation("bbMax"), 1, glm::value_ptr(bbmax));
    glUniform3f(this->lineShader.ParameterLocation("color"), color[0], color[1], color[2]);

    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);

    glEnable(GL_LIGHTING);
    glDisable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glDisable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    if (smoothLines) glDisable(GL_LINE_SMOOTH);
    glLineWidth(1.0f);
    glDisable(GL_CULL_FACE);
    glPolygonMode(GL_BACK, GL_FILL);

    this->lineShader.Disable();

    return true;
}

/*
 * BoundingBoxRenderer::RenderViewCube
 */
bool BoundingBoxRenderer::RenderViewCube(CallRender3D_2& call) { return true; }
<|endoftext|>


<commit_before>/**
 * @file mean_shift_impl.hpp
 * @author Shangtong Zhang
 *
 * Mean shift clustering implementation.
 */
#ifndef __MLPACK_METHODS_MEAN_SHIFT_MEAN_SHIFT_IMPL_HPP
#define __MLPACK_METHODS_MEAN_SHIFT_MEAN_SHIFT_IMPL_HPP

#include <mlpack/core/kernels/gaussian_kernel.hpp>
#include <mlpack/core/kernels/kernel_traits.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search_stat.hpp>

// In case it hasn't been included yet.
#include "mean_shift.hpp"

namespace mlpack {
namespace meanshift {

/**
  * Construct the Mean Shift object.
  */
template<typename KernelType, typename MatType>
MeanShift<KernelType, MatType>::MeanShift(const double radius,
                                          const size_t maxIterations,
                                          const KernelType kernel) :
    maxIterations(maxIterations),
    kernel(kernel),
    radius(radius)
{
  // Nothing to do.
}

template<typename KernelType, typename MatType>
void MeanShift<KernelType, MatType>::Radius(double radius)
{
  this->radius = radius;
}

// Estimate radius based on given dataset.
template<typename KernelType, typename MatType>
double MeanShift<KernelType, MatType>::EstimateRadius(const MatType &data)
{
  neighbor::NeighborSearch<
      neighbor::NearestNeighborSort,
      metric::EuclideanDistance,
      tree::BinarySpaceTree<bound::HRectBound<2>,
            neighbor::NeighborSearchStat<neighbor::NearestNeighborSort> >
  > neighborSearch(data);

  /**
   * For each point in dataset, select nNeighbors nearest points and get
   * nNeighbors distances.  Use the maximum distance to estimate the duplicate
   * threshhold.
   */
  size_t nNeighbors = size_t(data.n_cols * 0.3);
  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighborSearch.Search(nNeighbors, neighbors, distances);

  // Get max distance for each point.
  arma::rowvec maxDistances = max(distances);

  // Calculate and return the radius.
  return sum(maxDistances) / (double) data.n_cols;
}

// General way to calculate the weight of a data point.
template<typename KernelType, typename MatType>
bool MeanShift<KernelType, MatType>::CalcWeight(
    const arma::colvec& centroid,
    const arma::colvec& point,
    double& weight)
{
  double distance = metric::EuclideanDistance::Evaluate(centroid, point);
  if (distance >= radius || distance == 0)
    return false;

  distance /= radius;
  weight = kernel.Gradient(distance) / distance;
  return true;
}

/**
 * Perform Mean Shift clustering on the data, returning a list of cluster
 * assignments and centroids.
 */
template<typename KernelType, typename MatType>
inline void MeanShift<KernelType, MatType>::Cluster(
    const MatType& data,
    arma::Col<size_t>& assignments,
    arma::mat& centroids)
{
  if (radius <= 0)
  {
    // An invalid radius is given, an estimation is needed.
    Radius(EstimateRadius(data));
  }

  // Holds all centroids, before removing duplicate ones.
  arma::mat allCentroids(data.n_rows, data.n_cols);
  assignments.set_size(data.n_cols);

  // For each point in dataset, perform mean shift algorithm.
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Initial centroid is the point itself.
    allCentroids.col(i) = data.col(i);

    for (size_t completedIterations = 0; completedIterations < maxIterations;
         completedIterations++)
    {
      // Store new centroid in this.
      arma::Col<double> newCentroid = arma::zeros(data.n_rows, 1);

      double sumWeight = 0;

      // Go through all the points
      for (size_t j = 0; j < data.n_cols; ++j)
      {
        double weight = 0;
        if (CalcWeight(allCentroids.col(i), data.col(j), weight))
        {
          sumWeight += weight;
          newCentroid += weight * data.col(j);
        }
      }

      newCentroid /= sumWeight;

      // Calculate the mean shift vector.
      arma::Col<double> mhVector = newCentroid - allCentroids.col(i);

      // If the mean shift vector is small enough, it has converged.
      if (metric::EuclideanDistance::Evaluate(newCentroid, allCentroids.col(i))
          < 1e-3 * radius)
      {
        // Determine if the new centroid is duplicate with old ones.
        bool isDuplicated = false;
        for (size_t k = 0; k < centroids.n_cols; ++k)
        {
          arma::Col<double> delta = allCentroids.col(i) - centroids.col(k);
          if (norm(delta, 2) < radius)
          {
            isDuplicated = true;
            assignments(i) = k;
            break;
          }
        }

        if (!isDuplicated)
        {
          // This centroid is a new centroid.
          if (centroids.n_cols == 0)
          {
            centroids.insert_cols(0, allCentroids.col(i));
            assignments(i) = 0;
          }
          else
          {
            centroids.insert_cols(centroids.n_cols, allCentroids.col(i));
            assignments(i) = centroids.n_cols - 1;
          }
        }

        // Get out of the loop.
        break;
      }

      // Update the centroid.
      allCentroids.col(i) = newCentroid;
    }
  }
}

} // namespace meanshift
} // namespace mlpack

#endif
<commit_msg>Minor speedup.<commit_after>/**
 * @file mean_shift_impl.hpp
 * @author Shangtong Zhang
 *
 * Mean shift clustering implementation.
 */
#ifndef __MLPACK_METHODS_MEAN_SHIFT_MEAN_SHIFT_IMPL_HPP
#define __MLPACK_METHODS_MEAN_SHIFT_MEAN_SHIFT_IMPL_HPP

#include <mlpack/core/kernels/gaussian_kernel.hpp>
#include <mlpack/core/kernels/kernel_traits.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search_stat.hpp>

// In case it hasn't been included yet.
#include "mean_shift.hpp"

namespace mlpack {
namespace meanshift {

/**
  * Construct the Mean Shift object.
  */
template<typename KernelType, typename MatType>
MeanShift<KernelType, MatType>::MeanShift(const double radius,
                                          const size_t maxIterations,
                                          const KernelType kernel) :
    maxIterations(maxIterations),
    kernel(kernel),
    radius(radius)
{
  // Nothing to do.
}

template<typename KernelType, typename MatType>
void MeanShift<KernelType, MatType>::Radius(double radius)
{
  this->radius = radius;
}

// Estimate radius based on given dataset.
template<typename KernelType, typename MatType>
double MeanShift<KernelType, MatType>::EstimateRadius(const MatType &data)
{
  neighbor::NeighborSearch<
      neighbor::NearestNeighborSort,
      metric::EuclideanDistance,
      tree::BinarySpaceTree<bound::HRectBound<2>,
            neighbor::NeighborSearchStat<neighbor::NearestNeighborSort> >
  > neighborSearch(data);

  /**
   * For each point in dataset, select nNeighbors nearest points and get
   * nNeighbors distances.  Use the maximum distance to estimate the duplicate
   * threshhold.
   */
  size_t nNeighbors = size_t(data.n_cols * 0.3);
  arma::Mat<size_t> neighbors;
  arma::mat distances;
  neighborSearch.Search(nNeighbors, neighbors, distances);

  // Get max distance for each point.
  arma::rowvec maxDistances = max(distances);

  // Calculate and return the radius.
  return sum(maxDistances) / (double) data.n_cols;
}

// General way to calculate the weight of a data point.
template<typename KernelType, typename MatType>
bool MeanShift<KernelType, MatType>::CalcWeight(
    const arma::colvec& centroid,
    const arma::colvec& point,
    double& weight)
{
  double distance = metric::EuclideanDistance::Evaluate(centroid, point);
  if (distance >= radius || distance == 0)
    return false;

  distance /= radius;
  weight = kernel.Gradient(distance) / distance;
  return true;
}

/**
 * Perform Mean Shift clustering on the data, returning a list of cluster
 * assignments and centroids.
 */
template<typename KernelType, typename MatType>
inline void MeanShift<KernelType, MatType>::Cluster(
    const MatType& data,
    arma::Col<size_t>& assignments,
    arma::mat& centroids)
{
  if (radius <= 0)
  {
    // An invalid radius is given, an estimation is needed.
    Radius(EstimateRadius(data));
  }

  // Holds all centroids, before removing duplicate ones.
  arma::mat allCentroids(data.n_rows, data.n_cols);
  assignments.set_size(data.n_cols);

  // For each point in dataset, perform mean shift algorithm.
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Initial centroid is the point itself.
    allCentroids.col(i) = data.col(i);

    for (size_t completedIterations = 0; completedIterations < maxIterations;
         completedIterations++)
    {
      // Store new centroid in this.
      arma::Col<double> newCentroid = arma::zeros(data.n_rows, 1);

      double sumWeight = 0;

      // Go through all the points
      for (size_t j = 0; j < data.n_cols; ++j)
      {
        double weight = 0;
        if (CalcWeight(allCentroids.col(i), data.col(j), weight))
        {
          sumWeight += weight;
          newCentroid += weight * data.col(j);
        }
      }

      newCentroid /= sumWeight;

      // Calculate the mean shift vector.
      arma::Col<double> mhVector = newCentroid - allCentroids.col(i);

      // If the mean shift vector is small enough, it has converged.
      if (metric::EuclideanDistance::Evaluate(newCentroid, allCentroids.col(i))
          < 1e-3 * radius)
      {
        // Determine if the new centroid is duplicate with old ones.
        bool isDuplicated = false;
        for (size_t k = 0; k < centroids.n_cols; ++k)
        {
          const double distance = metric::EuclideanDistance::Evaluate(
              allCentroids.col(i), centroids.col(k));
          if (distance < radius)
          {
            isDuplicated = true;
            assignments(i) = k;
            break;
          }
        }

        if (!isDuplicated)
        {
          // This centroid is a new centroid.
          if (centroids.n_cols == 0)
          {
            centroids.insert_cols(0, allCentroids.col(i));
            assignments(i) = 0;
          }
          else
          {
            centroids.insert_cols(centroids.n_cols, allCentroids.col(i));
            assignments(i) = centroids.n_cols - 1;
          }
        }

        // Get out of the loop.
        break;
      }

      // Update the centroid.
      allCentroids.col(i) = newCentroid;
    }
  }
}

} // namespace meanshift
} // namespace mlpack

#endif
<|endoftext|>


<commit_before>//
//  MCIMAPMultiDisconnectOperation.cc
//  mailcore2
//
//  Created by Hoa V. DINH on 11/7/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCIMAPMultiDisconnectOperation.h"

using namespace mailcore;

IMAPMultiDisconnectOperation::IMAPMultiDisconnectOperation()
{
    _count = 0;
    _operations = new Array();
}

IMAPMultiDisconnectOperation::~IMAPMultiDisconnectOperation()
{
    MC_SAFE_RELEASE(_operations);
}

void IMAPMultiDisconnectOperation::addOperation(IMAPOperation * op)
{
    _operations->addObject(op);
}

void IMAPMultiDisconnectOperation::start()
{
    mc_foreacharray(IMAPOperation, op, _operations) {
        op->setCallback(this);
        op->start();
    }
}

void IMAPMultiDisconnectOperation::operationFinished(Operation * op)
{
    _count ++;
    if (_count == _operations->count()) {
        callback()->operationFinished(this);
    }
}

<commit_msg>Fixed disconnect operation behavior when no connection is established<commit_after>//
//  MCIMAPMultiDisconnectOperation.cc
//  mailcore2
//
//  Created by Hoa V. DINH on 11/7/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCIMAPMultiDisconnectOperation.h"

using namespace mailcore;

IMAPMultiDisconnectOperation::IMAPMultiDisconnectOperation()
{
    _count = 0;
    _operations = new Array();
}

IMAPMultiDisconnectOperation::~IMAPMultiDisconnectOperation()
{
    MC_SAFE_RELEASE(_operations);
}

void IMAPMultiDisconnectOperation::addOperation(IMAPOperation * op)
{
    _operations->addObject(op);
}

void IMAPMultiDisconnectOperation::start()
{
    if (_operations->count() == 0) {
        callback()->operationFinished(this);
        return;
    }

    mc_foreacharray(IMAPOperation, op, _operations) {
        op->setCallback(this);
        op->start();
    }
}

void IMAPMultiDisconnectOperation::operationFinished(Operation * op)
{
    _count ++;
    if (_count == _operations->count()) {
        callback()->operationFinished(this);
    }
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "acm_gsmfr.h"
#include "acm_common_defs.h"
#include "acm_gsmfr.h"
#include "acm_neteq.h"
#include "trace.h"
#include "webrtc_neteq.h"
#include "webrtc_neteq_help_macros.h"

#ifdef WEBRTC_CODEC_GSMFR
    // NOTE! GSM-FR is not included in the open-source package. A wrapper is
    // needed with interface file named as below. The API should match the one
    // below.
    //
    // int16_t WebRtcGSMFR_CreateEnc(GSMFR_encinst_t_** inst);
    // int16_t WebRtcGSMFR_CreateDec(GSMFR_decinst_t_** inst);
    // int16_t WebRtcGSMFR_FreeEnc(GSMFR_encinst_t_* inst);
    // int16_t WebRtcGSMFR_FreeDec(GSMFR_decinst_t_* inst);
    // int16_t WebRtcGSMFR_Encode(GSMFR_encinst_t_* encInst, int16_t* input,
    //                            int16_t len, int16_t* output);
    // int16_t WebRtcGSMFR_EncoderInit(GSMFR_encinst_t_* encInst, int16_t mode);
    // int16_t WebRtcGSMFR_Decode(GSMFR_decinst_t_* decInst);
    // int16_t WebRtcGSMFR_DecodeBwe(GSMFR_decinst_t_* decInst, int16_t* input);
    // int16_t WebRtcGSMFR_DecodePlc(GSMFR_decinst_t_* decInst);
    // int16_t WebRtcGSMFR_DecoderInit(GSMFR_decinst_t_* decInst);
    #include "gsmfr_interface.h"
#endif

namespace webrtc {

#ifndef WEBRTC_CODEC_GSMFR

ACMGSMFR::ACMGSMFR(
    WebRtc_Word16 /* codecID */)
{
    return;
}

ACMGSMFR::~ACMGSMFR()
{
    return;
}

WebRtc_Word16
ACMGSMFR::InternalEncode(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16* /* bitStreamLenByte */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::DecodeSafe(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16  /* bitStreamLenByte */,
    WebRtc_Word16* /* audio            */,
    WebRtc_Word16* /* audioSamples     */,
    WebRtc_Word8*  /* speechType       */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::EnableDTX()
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::DisableDTX()
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::InternalInitEncoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::InternalInitDecoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    return -1;
}

WebRtc_Word32
ACMGSMFR::CodecDef(
    WebRtcNetEQ_CodecDef& /* codecDef  */,
    const CodecInst&      /* codecInst */)
{
    return -1;
}

ACMGenericCodec*
ACMGSMFR::CreateInstance(void)
{
    return NULL;
}

WebRtc_Word16
ACMGSMFR::InternalCreateEncoder()
{
    return -1;
}

void
ACMGSMFR::DestructEncoderSafe()
{
    return;
}

WebRtc_Word16
ACMGSMFR::InternalCreateDecoder()
{
    return -1;
}

void
ACMGSMFR::DestructDecoderSafe()
{
    return;
}

void
ACMGSMFR::InternalDestructEncoderInst(
    void* /* ptrInst */)
{
    return;
}

WebRtc_Word16
ACMGSMFR::UnregisterFromNetEqSafe(
    ACMNetEQ*     /* netEq       */,
    WebRtc_Word16 /* payloadType */)
{
    return -1;
}

#else     //===================== Actual Implementation =======================

ACMGSMFR::ACMGSMFR(
    WebRtc_Word16 codecID):
_encoderInstPtr(NULL),
_decoderInstPtr(NULL)
{
    _codecID = codecID;
    _hasInternalDTX = true;
    return;
}

ACMGSMFR::~ACMGSMFR()
{
    if(_encoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeEnc(_encoderInstPtr);
        _encoderInstPtr = NULL;
    }
    if(_decoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeDec(_decoderInstPtr);
        _decoderInstPtr = NULL;
    }
    return;
}

WebRtc_Word16
ACMGSMFR::InternalEncode(
    WebRtc_UWord8* bitStream,
    WebRtc_Word16* bitStreamLenByte)
{
    *bitStreamLenByte = WebRtcGSMFR_Encode(_encoderInstPtr,
        &_inAudio[_inAudioIxRead], _frameLenSmpl, (WebRtc_Word16*)bitStream);
    // increment the read index this tell the caller that how far
    // we have gone forward in reading the audio buffer
    _inAudioIxRead += _frameLenSmpl;
    return *bitStreamLenByte;
}

WebRtc_Word16
ACMGSMFR::DecodeSafe(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16  /* bitStreamLenByte */,
    WebRtc_Word16* /* audio            */,
    WebRtc_Word16* /* audioSamples     */,
    WebRtc_Word8*  /* speechType       */)
{
    return 0;
}

WebRtc_Word16
ACMGSMFR::EnableDTX()
{
    if(_dtxEnabled)
    {
        return 0;
    }
    else if(_encoderExist)
    {
        if(WebRtcGSMFR_EncoderInit(_encoderInstPtr, 1) < 0)
        {
			WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
				"EnableDTX: cannot init encoder for GSMFR");
            return -1;
        }
        _dtxEnabled = true;
        return 0;
    }
    else
    {
        return -1;
    }
}

WebRtc_Word16
ACMGSMFR::DisableDTX()
{
    if(!_dtxEnabled)
    {
        return 0;
    }
    else if(_encoderExist)
    {
        if(WebRtcGSMFR_EncoderInit(_encoderInstPtr, 0) < 0)
        {
			WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
				"DisableDTX: cannot init encoder for GSMFR");
            return -1;
        }
        _dtxEnabled = false;
        return 0;
    }
    else
    {
        // encoder doesn't exists, therefore disabling is harmless
        return 0;
    }
}

WebRtc_Word16
ACMGSMFR::InternalInitEncoder(
    WebRtcACMCodecParams* codecParams)
{
    if (WebRtcGSMFR_EncoderInit(_encoderInstPtr, ((codecParams->enableDTX)? 1:0)) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"InternalInitEncoder: cannot init encoder for GSMFR");
	}
	return 0;
}

WebRtc_Word16
ACMGSMFR::InternalInitDecoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    if (WebRtcGSMFR_DecoderInit(_decoderInstPtr) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalInitDecoder: cannot init decoder for GSMFR");
		return -1;
	}
	return 0;
}

WebRtc_Word32
ACMGSMFR::CodecDef(
    WebRtcNetEQ_CodecDef& codecDef,
    const CodecInst&      codecInst)
{
    if (!_decoderInitialized)
    {
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"CodecDef: decoder is not initialized for GSMFR");
        return -1;
    }
    // Fill up the structure by calling
    // "SET_CODEC_PAR" & "SET_GSMFR_FUNCTION."
    // Then call NetEQ to add the codec to it's
    // database.
    SET_CODEC_PAR((codecDef), kDecoderGSMFR, codecInst.pltype,
        _decoderInstPtr, 8000);
    SET_GSMFR_FUNCTIONS((codecDef));
    return 0;
}

ACMGenericCodec*
ACMGSMFR::CreateInstance(void)
{
    return NULL;
}

WebRtc_Word16
ACMGSMFR::InternalCreateEncoder()
{
    if (WebRtcGSMFR_CreateEnc(&_encoderInstPtr) < 0)
	{
		 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalCreateEncoder: cannot create instance for GSMFR encoder");
		return -1;
	}
	return 0;
}

void
ACMGSMFR::DestructEncoderSafe()
{
    if(_encoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeEnc(_encoderInstPtr);
        _encoderInstPtr = NULL;
    }
    _encoderExist = false;
    _encoderInitialized = false;
}

WebRtc_Word16
ACMGSMFR::InternalCreateDecoder()
{
    if (WebRtcGSMFR_CreateDec(&_decoderInstPtr) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalCreateDecoder: cannot create instance for GSMFR decoder");
		return -1;
	}
	return 0;
}

void
ACMGSMFR::DestructDecoderSafe()
{
    if(_decoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeDec(_decoderInstPtr);
        _decoderInstPtr = NULL;
    }
    _decoderExist = false;
    _decoderInitialized = false;
}

void
ACMGSMFR::InternalDestructEncoderInst(
    void* ptrInst)
{
    if(ptrInst != NULL)
    {
        WebRtcGSMFR_FreeEnc((GSMFR_encinst_t_*)ptrInst);
    }
    return;
}

WebRtc_Word16
ACMGSMFR::UnregisterFromNetEqSafe(
    ACMNetEQ*     netEq,
    WebRtc_Word16 payloadType)
{
    if(payloadType != _decoderParams.codecInstant.pltype)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"Cannot unregister codec: payload-type does not match \
the stored payload type",
            _decoderParams.codecInstant.plname,
            payloadType,
            _decoderParams.codecInstant.pltype);
        return -1;
    }
    return netEq->RemoveCodec(kDecoderGSMFR);
}

#endif

} // namespace webrtc
<commit_msg>header included twice. Review URL: http://webrtc-codereview.appspot.com/139013<commit_after>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "acm_gsmfr.h"
#include "acm_common_defs.h"
#include "acm_neteq.h"
#include "trace.h"
#include "webrtc_neteq.h"
#include "webrtc_neteq_help_macros.h"

#ifdef WEBRTC_CODEC_GSMFR
    // NOTE! GSM-FR is not included in the open-source package. A wrapper is
    // needed with interface file named as below. The API should match the one
    // below.
    //
    // int16_t WebRtcGSMFR_CreateEnc(GSMFR_encinst_t_** inst);
    // int16_t WebRtcGSMFR_CreateDec(GSMFR_decinst_t_** inst);
    // int16_t WebRtcGSMFR_FreeEnc(GSMFR_encinst_t_* inst);
    // int16_t WebRtcGSMFR_FreeDec(GSMFR_decinst_t_* inst);
    // int16_t WebRtcGSMFR_Encode(GSMFR_encinst_t_* encInst, int16_t* input,
    //                            int16_t len, int16_t* output);
    // int16_t WebRtcGSMFR_EncoderInit(GSMFR_encinst_t_* encInst, int16_t mode);
    // int16_t WebRtcGSMFR_Decode(GSMFR_decinst_t_* decInst);
    // int16_t WebRtcGSMFR_DecodeBwe(GSMFR_decinst_t_* decInst, int16_t* input);
    // int16_t WebRtcGSMFR_DecodePlc(GSMFR_decinst_t_* decInst);
    // int16_t WebRtcGSMFR_DecoderInit(GSMFR_decinst_t_* decInst);
    #include "gsmfr_interface.h"
#endif

namespace webrtc {

#ifndef WEBRTC_CODEC_GSMFR

ACMGSMFR::ACMGSMFR(
    WebRtc_Word16 /* codecID */)
{
    return;
}

ACMGSMFR::~ACMGSMFR()
{
    return;
}

WebRtc_Word16
ACMGSMFR::InternalEncode(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16* /* bitStreamLenByte */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::DecodeSafe(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16  /* bitStreamLenByte */,
    WebRtc_Word16* /* audio            */,
    WebRtc_Word16* /* audioSamples     */,
    WebRtc_Word8*  /* speechType       */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::EnableDTX()
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::DisableDTX()
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::InternalInitEncoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    return -1;
}

WebRtc_Word16
ACMGSMFR::InternalInitDecoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    return -1;
}

WebRtc_Word32
ACMGSMFR::CodecDef(
    WebRtcNetEQ_CodecDef& /* codecDef  */,
    const CodecInst&      /* codecInst */)
{
    return -1;
}

ACMGenericCodec*
ACMGSMFR::CreateInstance(void)
{
    return NULL;
}

WebRtc_Word16
ACMGSMFR::InternalCreateEncoder()
{
    return -1;
}

void
ACMGSMFR::DestructEncoderSafe()
{
    return;
}

WebRtc_Word16
ACMGSMFR::InternalCreateDecoder()
{
    return -1;
}

void
ACMGSMFR::DestructDecoderSafe()
{
    return;
}

void
ACMGSMFR::InternalDestructEncoderInst(
    void* /* ptrInst */)
{
    return;
}

WebRtc_Word16
ACMGSMFR::UnregisterFromNetEqSafe(
    ACMNetEQ*     /* netEq       */,
    WebRtc_Word16 /* payloadType */)
{
    return -1;
}

#else     //===================== Actual Implementation =======================

ACMGSMFR::ACMGSMFR(
    WebRtc_Word16 codecID):
_encoderInstPtr(NULL),
_decoderInstPtr(NULL)
{
    _codecID = codecID;
    _hasInternalDTX = true;
    return;
}

ACMGSMFR::~ACMGSMFR()
{
    if(_encoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeEnc(_encoderInstPtr);
        _encoderInstPtr = NULL;
    }
    if(_decoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeDec(_decoderInstPtr);
        _decoderInstPtr = NULL;
    }
    return;
}

WebRtc_Word16
ACMGSMFR::InternalEncode(
    WebRtc_UWord8* bitStream,
    WebRtc_Word16* bitStreamLenByte)
{
    *bitStreamLenByte = WebRtcGSMFR_Encode(_encoderInstPtr,
        &_inAudio[_inAudioIxRead], _frameLenSmpl, (WebRtc_Word16*)bitStream);
    // increment the read index this tell the caller that how far
    // we have gone forward in reading the audio buffer
    _inAudioIxRead += _frameLenSmpl;
    return *bitStreamLenByte;
}

WebRtc_Word16
ACMGSMFR::DecodeSafe(
    WebRtc_UWord8* /* bitStream        */,
    WebRtc_Word16  /* bitStreamLenByte */,
    WebRtc_Word16* /* audio            */,
    WebRtc_Word16* /* audioSamples     */,
    WebRtc_Word8*  /* speechType       */)
{
    return 0;
}

WebRtc_Word16
ACMGSMFR::EnableDTX()
{
    if(_dtxEnabled)
    {
        return 0;
    }
    else if(_encoderExist)
    {
        if(WebRtcGSMFR_EncoderInit(_encoderInstPtr, 1) < 0)
        {
			WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
				"EnableDTX: cannot init encoder for GSMFR");
            return -1;
        }
        _dtxEnabled = true;
        return 0;
    }
    else
    {
        return -1;
    }
}

WebRtc_Word16
ACMGSMFR::DisableDTX()
{
    if(!_dtxEnabled)
    {
        return 0;
    }
    else if(_encoderExist)
    {
        if(WebRtcGSMFR_EncoderInit(_encoderInstPtr, 0) < 0)
        {
			WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
				"DisableDTX: cannot init encoder for GSMFR");
            return -1;
        }
        _dtxEnabled = false;
        return 0;
    }
    else
    {
        // encoder doesn't exists, therefore disabling is harmless
        return 0;
    }
}

WebRtc_Word16
ACMGSMFR::InternalInitEncoder(
    WebRtcACMCodecParams* codecParams)
{
    if (WebRtcGSMFR_EncoderInit(_encoderInstPtr, ((codecParams->enableDTX)? 1:0)) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"InternalInitEncoder: cannot init encoder for GSMFR");
	}
	return 0;
}

WebRtc_Word16
ACMGSMFR::InternalInitDecoder(
    WebRtcACMCodecParams* /* codecParams */)
{
    if (WebRtcGSMFR_DecoderInit(_decoderInstPtr) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalInitDecoder: cannot init decoder for GSMFR");
		return -1;
	}
	return 0;
}

WebRtc_Word32
ACMGSMFR::CodecDef(
    WebRtcNetEQ_CodecDef& codecDef,
    const CodecInst&      codecInst)
{
    if (!_decoderInitialized)
    {
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"CodecDef: decoder is not initialized for GSMFR");
        return -1;
    }
    // Fill up the structure by calling
    // "SET_CODEC_PAR" & "SET_GSMFR_FUNCTION."
    // Then call NetEQ to add the codec to it's
    // database.
    SET_CODEC_PAR((codecDef), kDecoderGSMFR, codecInst.pltype,
        _decoderInstPtr, 8000);
    SET_GSMFR_FUNCTIONS((codecDef));
    return 0;
}

ACMGenericCodec*
ACMGSMFR::CreateInstance(void)
{
    return NULL;
}

WebRtc_Word16
ACMGSMFR::InternalCreateEncoder()
{
    if (WebRtcGSMFR_CreateEnc(&_encoderInstPtr) < 0)
	{
		 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalCreateEncoder: cannot create instance for GSMFR encoder");
		return -1;
	}
	return 0;
}

void
ACMGSMFR::DestructEncoderSafe()
{
    if(_encoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeEnc(_encoderInstPtr);
        _encoderInstPtr = NULL;
    }
    _encoderExist = false;
    _encoderInitialized = false;
}

WebRtc_Word16
ACMGSMFR::InternalCreateDecoder()
{
    if (WebRtcGSMFR_CreateDec(&_decoderInstPtr) < 0)
	{
		WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			 "InternalCreateDecoder: cannot create instance for GSMFR decoder");
		return -1;
	}
	return 0;
}

void
ACMGSMFR::DestructDecoderSafe()
{
    if(_decoderInstPtr != NULL)
    {
        WebRtcGSMFR_FreeDec(_decoderInstPtr);
        _decoderInstPtr = NULL;
    }
    _decoderExist = false;
    _decoderInitialized = false;
}

void
ACMGSMFR::InternalDestructEncoderInst(
    void* ptrInst)
{
    if(ptrInst != NULL)
    {
        WebRtcGSMFR_FreeEnc((GSMFR_encinst_t_*)ptrInst);
    }
    return;
}

WebRtc_Word16
ACMGSMFR::UnregisterFromNetEqSafe(
    ACMNetEQ*     netEq,
    WebRtc_Word16 payloadType)
{
    if(payloadType != _decoderParams.codecInstant.pltype)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
			"Cannot unregister codec: payload-type does not match \
the stored payload type",
            _decoderParams.codecInstant.plname,
            payloadType,
            _decoderParams.codecInstant.pltype);
        return -1;
    }
    return netEq->RemoveCodec(kDecoderGSMFR);
}

#endif

} // namespace webrtc
<|endoftext|>


<commit_before><commit_msg>commit<commit_after>#include <stdio.h>
#include <string.h>

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

#define N 100100

int n, k, ans;

int fa[N], rank[N];

void init() {
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
}

int find(int v) {
    if (fa[v] == v) return v;
    else {
        int temp = fa[v];
        fa[v] = find(fa[v]);
        rank[v] = (rank[v] + rank[temp])%3;
    }
    return fa[v];
}

bool check(int x, int y, int d) {
    if (x > n || y > n) return false; //rule no.2
    if (d == 1 && x == y) return false; //rule no.3 , already minus by 1

    int fx = find(x);
    int fy = find(y);

    if (fx == fy) {
        int rxy = ((rank[x]-rank[y])%3+3)%3;
        return rxy == d;
    }
    return true;
}

void merge(int x, int y, int d) {
    int fx = find(x);
    int fy = find(y);

    if (fx != fy) {
        fa[fx] = fy;
        rank[fx] = (d + rank[y]-rank[x]+3)%3;
    }
}

int main () {
    cin >> n >> k;
    ans = 0;
    ::memset(fa, 0, sizeof(fa));
    ::memset(rank, 0, sizeof(rank));
    init();
    int d, x, y;
    for (int i = 0; i < k; i++) {
        cin >> d >> x >> y;
        if (!check(x, y, d-1)) {
            ans++;
        } else {
            merge(x, y, d-1);
        }
    }
    printf("%d\n", ans);
    return 0;
}
<|endoftext|>


<commit_before>#include <erl_nif.h>
#include <cstdio>

#include "exc.hpp"
#include "async_queue.h"
#include "snappy.h"
#include "snappy-sinksource.h"

static const size_t ALLOC_SIZE = 2048;

class Sink: public snappy::Sink {
public:

    Sink(): used(0)
    {
        if (!enif_alloc_binary(0, &bin)) {
            enif_release_binary(&bin);
            THROW_EXC("enif_alloc_binary() failed");
        }
    }

    void Append(const char *data, size_t n)
    {
        if (data != reinterpret_cast<const char*>(bin.data + used)) {
            memcpy(bin.data + used, data, n);
        }

        used += n;
    }

    char* GetAppendBuffer(size_t len, char*)
    {
        size_t allocated = bin.size;

        if ((used + len) > allocated) {
            size_t sz = len > ALLOC_SIZE ? len + ALLOC_SIZE - (len % ALLOC_SIZE) : ALLOC_SIZE;

            if (!enif_realloc_binary(&bin, allocated + sz)) {
                enif_release_binary(&bin);
                THROW_EXC("enif_realloc_binary() failed");
            }
        }

        return reinterpret_cast<char*>(bin.data + used);
    }

    ErlNifBinary& GetBinary()
    {
        size_t allocated = bin.size;

        if (allocated > used) {
            if (!enif_realloc_binary(&bin, used)) {
                enif_release_binary(&bin);
                THROW_EXC("enif_realloc_binary() failed");
            }
        }

        return bin;
    }

private:

    ErlNifBinary  bin;
    size_t        used;
};

extern "C" {

typedef struct {
    async_queue_t    *queue;
    ErlNifThreadOpts *topts;
    ErlNifTid         tid;
} ctx_t;

typedef enum {
    UNKNOWN,
    COMPRESS,
    DECOMPRESS,
    SHUTDOWN
} task_type_t;

typedef struct {
    task_type_t   type;
    ErlNifEnv    *env;
    ErlNifPid     pid;
    ERL_NIF_TERM  ref;
    ErlNifBinary  data;
} task_t;

static ErlNifResourceType *res_type;
static ERL_NIF_TERM        atom_ok;
static ERL_NIF_TERM        atom_error;

static void cleanup_task(task_t **task);
static task_t* init_task(task_type_t type, ERL_NIF_TERM ref, ErlNifPid pid,
    ERL_NIF_TERM orig_term);
static task_t* init_empty_task(task_type_t type);
static ctx_t* init_ctx();
static ERL_NIF_TERM compress(task_t *task);
static ERL_NIF_TERM decompress(task_t *task);
static void* worker(void *arg);

void resource_dtor(ErlNifEnv *env, void *obj);
int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info);

void
cleanup_task(task_t **task)
{
    if ((*task)->env != NULL) {
        enif_free_env((*task)->env);
    }

    enif_free(*task);
    *task = NULL;
}

task_t*
init_empty_task(task_type_t type)
{
    task_t *task;

    task = static_cast<task_t*>(enif_alloc(sizeof(*task)));

    if (task == NULL) {
        goto done;
    }

    memset(task, 0, sizeof(*task));
    task->type = type;

done:
    return task;
}

task_t*
init_task(task_type_t type, ERL_NIF_TERM ref, ErlNifPid pid,
    ERL_NIF_TERM orig_term)
{
    ERL_NIF_TERM  term;
    task_t       *task;

    task = init_empty_task(type);

    task->pid = pid;
    task->env = enif_alloc_env();

    if (task->env == NULL) {
        cleanup_task(&task);
        goto done;
    }

    term = enif_make_copy(task->env, orig_term);

    if (!enif_inspect_iolist_as_binary(task->env, term, &task->data)) {
        cleanup_task(&task);
        goto done;
    }

    task->ref = enif_make_copy(task->env, ref);

done:
    return task;
}

ERL_NIF_TERM
compress(task_t *task)
{
    ERL_NIF_TERM result;

    snappy::ByteArraySource source(reinterpret_cast<const char*>(task->data.data), task->data.size);

    Sink sink;

    try {
        snappy::Compress(&source, &sink);
        result = enif_make_tuple3(task->env, atom_ok, task->ref,
            enif_make_binary(task->env, &sink.GetBinary()));
    } catch (std::exception &e) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Failed to compress",
                ERL_NIF_LATIN1));
    }

    return result;
}

ERL_NIF_TERM
decompress(task_t *task)
{
    size_t len;
    bool   status;

    ERL_NIF_TERM result;
    ErlNifBinary bin;

    len = -1;
    status = snappy::GetUncompressedLength(
        reinterpret_cast<const char *>(task->data.data),
        task->data.size, &len);

    if (!status) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Data is not compressed",
                ERL_NIF_LATIN1));
        goto done;
    }

    if (!enif_alloc_binary(len, &bin)) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Couldn't allocate memory",
                ERL_NIF_LATIN1));
        goto done;
    }

    status = snappy::RawUncompress(
        reinterpret_cast<const char*>(task->data.data),
        task->data.size, reinterpret_cast<char*>(bin.data));

    if (!status) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Failed to decompress",
                ERL_NIF_LATIN1));
        goto done;
    }

    result = enif_make_tuple3(task->env, atom_ok, task->ref,
        enif_make_binary(task->env, &bin));

done:
    return result;
}

void*
worker(void *arg)
{
    ctx_t  *ctx;
    task_t *task;

    ERL_NIF_TERM result;

    ctx = static_cast<ctx_t*>(arg);

    while (true) {
        task = static_cast<task_t*>(async_queue_pop(ctx->queue));

        if (task->type == COMPRESS) {
            result = compress(task);
        } else if (task->type == DECOMPRESS) {
            result = decompress(task);
        } else if (task->type == SHUTDOWN) {
            break;
        } else {
            errx(1, "Unexpected task type: %i", task->type);
        }

        enif_send(NULL, &task->pid, task->env, result);
        cleanup_task(&task);
    }

    cleanup_task(&task);
    return NULL;
}

ctx_t*
init_ctx()
{
    int status;

    ctx_t *ctx = static_cast<ctx_t*>(enif_alloc_resource(res_type, sizeof(*ctx)));

    if (ctx == NULL) {
        goto done;
    }

    ctx->queue = async_queue_create();
    ctx->topts = enif_thread_opts_create(const_cast<char*>("snappy_thread_opts"));

    status = enif_thread_create(const_cast<char*>("worker"),
        &ctx->tid, worker, ctx, ctx->topts);

    if (status != 0) {
        enif_release_resource(ctx);
        ctx = NULL;
        goto done;
    }

done:
    return ctx;
}

void
resource_dtor(ErlNifEnv *env, void *obj)
{
    ctx_t  *ctx = static_cast<ctx_t*>(obj);
    task_t *task = init_empty_task(SHUTDOWN);
    void   *result = NULL;

    async_queue_push(ctx->queue, static_cast<void*>(task));
    enif_thread_join(ctx->tid, &result);
    async_queue_destroy(ctx->queue);
    enif_thread_opts_destroy(ctx->topts);
}

int
load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
    const char *mod = "erlang-snappy";
    const char *name = "nif_resource";

    ErlNifResourceFlags flags = static_cast<ErlNifResourceFlags>(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);

    res_type = enif_open_resource_type(env, mod, name, resource_dtor, flags, NULL);

    if (res_type == NULL) {
        return -1;
    }

    atom_ok = enif_make_atom(env, "ok");
    atom_error = enif_make_atom(env, "error");

    return 0;
}

ERL_NIF_TERM
snappy_create_ctx(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    ERL_NIF_TERM  rv;
    ctx_t        *ctx;

    ctx = init_ctx();

    if (ctx == NULL) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create context",
                ERL_NIF_LATIN1));
    }

    rv = enif_make_resource(env, ctx);
    enif_release_resource(ctx);

    return enif_make_tuple2(env, atom_ok, rv);
}

ERL_NIF_TERM
snappy_compress_impl(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    ctx_t  *ctx;
    task_t *task;

    ErlNifPid pid;

    if (argc != 4) {
        return enif_make_badarg(env);
    }

    if (!enif_get_resource(env, argv[0], res_type,
            reinterpret_cast<void**>(&ctx))) {
        return enif_make_badarg(env);
    }

    if (!enif_is_ref(env, argv[1])) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Second arg. is not a reference",
                ERL_NIF_LATIN1));
    }

    if (!enif_get_local_pid(env, argv[2], &pid)) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Third arg. is not a pid of local process",
                ERL_NIF_LATIN1));
    }

    if (!(enif_is_binary(env, argv[3]) ||
          enif_is_list(env, argv[3]))) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Forth arg. is not a binary or a list",
                ERL_NIF_LATIN1));
    }

    task = init_task(COMPRESS, argv[1], pid, argv[3]);

    if (!task) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create a task",
                ERL_NIF_LATIN1));
    }

    async_queue_push(ctx->queue, static_cast<void*>(task));

    return atom_ok;
}

ERL_NIF_TERM
snappy_decompress_impl(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    ctx_t  *ctx;
    task_t *task;

    ErlNifPid pid;

    if (argc != 4) {
        return enif_make_badarg(env);
    }

    if (!enif_get_resource(env, argv[0], res_type,
            reinterpret_cast<void**>(&ctx))) {
        return enif_make_badarg(env);
    }

    if (!enif_is_ref(env, argv[1])) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Second arg. is not a reference",
                ERL_NIF_LATIN1));
    }

    if (!enif_get_local_pid(env, argv[2], &pid)) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Third arg. is not a pid of local process",
                ERL_NIF_LATIN1));
    }

    if (!(enif_is_binary(env, argv[3]) ||
          enif_is_list(env, argv[3]))) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Forth arg. is not a binary",
                ERL_NIF_LATIN1));
    }

    task = init_task(DECOMPRESS, argv[1], pid, argv[3]);

    if (!task) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create a task",
                ERL_NIF_LATIN1));
    }

    async_queue_push(ctx->queue, static_cast<void*>(task));

    return atom_ok;
}

static ErlNifFunc nif_funcs[] = {
    {"create_ctx", 0, snappy_create_ctx},
    {"compress_impl", 4, snappy_compress_impl},
    {"decompress_impl", 4, snappy_decompress_impl}
};

ERL_NIF_INIT(esnappy, nif_funcs, &load, NULL, NULL, NULL);

} // extern "C"
<commit_msg>make C++ compiler happy by not naming unused args in functions' calls.<commit_after>#include <erl_nif.h>
#include <cstdio>

#include "exc.hpp"
#include "async_queue.h"
#include "snappy.h"
#include "snappy-sinksource.h"

static const size_t ALLOC_SIZE = 2048;

class Sink: public snappy::Sink {
public:

    Sink(): used(0)
    {
        if (!enif_alloc_binary(0, &bin)) {
            enif_release_binary(&bin);
            THROW_EXC("enif_alloc_binary() failed");
        }
    }

    void Append(const char *data, size_t n)
    {
        if (data != reinterpret_cast<const char*>(bin.data + used)) {
            memcpy(bin.data + used, data, n);
        }

        used += n;
    }

    char* GetAppendBuffer(size_t len, char*)
    {
        size_t allocated = bin.size;

        if ((used + len) > allocated) {
            size_t sz = len > ALLOC_SIZE ? len + ALLOC_SIZE - (len % ALLOC_SIZE) : ALLOC_SIZE;

            if (!enif_realloc_binary(&bin, allocated + sz)) {
                enif_release_binary(&bin);
                THROW_EXC("enif_realloc_binary() failed");
            }
        }

        return reinterpret_cast<char*>(bin.data + used);
    }

    ErlNifBinary& GetBinary()
    {
        size_t allocated = bin.size;

        if (allocated > used) {
            if (!enif_realloc_binary(&bin, used)) {
                enif_release_binary(&bin);
                THROW_EXC("enif_realloc_binary() failed");
            }
        }

        return bin;
    }

private:

    ErlNifBinary  bin;
    size_t        used;
};

extern "C" {

typedef struct {
    async_queue_t    *queue;
    ErlNifThreadOpts *topts;
    ErlNifTid         tid;
} ctx_t;

typedef enum {
    UNKNOWN,
    COMPRESS,
    DECOMPRESS,
    SHUTDOWN
} task_type_t;

typedef struct {
    task_type_t   type;
    ErlNifEnv    *env;
    ErlNifPid     pid;
    ERL_NIF_TERM  ref;
    ErlNifBinary  data;
} task_t;

static ErlNifResourceType *res_type;
static ERL_NIF_TERM        atom_ok;
static ERL_NIF_TERM        atom_error;

static void cleanup_task(task_t **task);
static task_t* init_task(task_type_t type, ERL_NIF_TERM ref, ErlNifPid pid,
    ERL_NIF_TERM orig_term);
static task_t* init_empty_task(task_type_t type);
static ctx_t* init_ctx();
static ERL_NIF_TERM compress(task_t *task);
static ERL_NIF_TERM decompress(task_t *task);
static void* worker(void *arg);

void resource_dtor(ErlNifEnv *env, void *obj);
int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info);

void
cleanup_task(task_t **task)
{
    if ((*task)->env != NULL) {
        enif_free_env((*task)->env);
    }

    enif_free(*task);
    *task = NULL;
}

task_t*
init_empty_task(task_type_t type)
{
    task_t *task;

    task = static_cast<task_t*>(enif_alloc(sizeof(*task)));

    if (task == NULL) {
        goto done;
    }

    memset(task, 0, sizeof(*task));
    task->type = type;

done:
    return task;
}

task_t*
init_task(task_type_t type, ERL_NIF_TERM ref, ErlNifPid pid,
    ERL_NIF_TERM orig_term)
{
    ERL_NIF_TERM  term;
    task_t       *task;

    task = init_empty_task(type);

    task->pid = pid;
    task->env = enif_alloc_env();

    if (task->env == NULL) {
        cleanup_task(&task);
        goto done;
    }

    term = enif_make_copy(task->env, orig_term);

    if (!enif_inspect_iolist_as_binary(task->env, term, &task->data)) {
        cleanup_task(&task);
        goto done;
    }

    task->ref = enif_make_copy(task->env, ref);

done:
    return task;
}

ERL_NIF_TERM
compress(task_t *task)
{
    ERL_NIF_TERM result;

    snappy::ByteArraySource source(reinterpret_cast<const char*>(task->data.data), task->data.size);

    Sink sink;

    try {
        snappy::Compress(&source, &sink);
        result = enif_make_tuple3(task->env, atom_ok, task->ref,
            enif_make_binary(task->env, &sink.GetBinary()));
    } catch (std::exception &e) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Failed to compress",
                ERL_NIF_LATIN1));
    }

    return result;
}

ERL_NIF_TERM
decompress(task_t *task)
{
    size_t len;
    bool   status;

    ERL_NIF_TERM result;
    ErlNifBinary bin;

    len = -1;
    status = snappy::GetUncompressedLength(
        reinterpret_cast<const char *>(task->data.data),
        task->data.size, &len);

    if (!status) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Data is not compressed",
                ERL_NIF_LATIN1));
        goto done;
    }

    if (!enif_alloc_binary(len, &bin)) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Couldn't allocate memory",
                ERL_NIF_LATIN1));
        goto done;
    }

    status = snappy::RawUncompress(
        reinterpret_cast<const char*>(task->data.data),
        task->data.size, reinterpret_cast<char*>(bin.data));

    if (!status) {
        result = enif_make_tuple2(task->env, atom_error,
            enif_make_string(task->env, "Failed to decompress",
                ERL_NIF_LATIN1));
        goto done;
    }

    result = enif_make_tuple3(task->env, atom_ok, task->ref,
        enif_make_binary(task->env, &bin));

done:
    return result;
}

void*
worker(void *arg)
{
    ctx_t  *ctx;
    task_t *task;

    ERL_NIF_TERM result;

    ctx = static_cast<ctx_t*>(arg);

    while (true) {
        task = static_cast<task_t*>(async_queue_pop(ctx->queue));

        if (task->type == COMPRESS) {
            result = compress(task);
        } else if (task->type == DECOMPRESS) {
            result = decompress(task);
        } else if (task->type == SHUTDOWN) {
            break;
        } else {
            errx(1, "Unexpected task type: %i", task->type);
        }

        enif_send(NULL, &task->pid, task->env, result);
        cleanup_task(&task);
    }

    cleanup_task(&task);
    return NULL;
}

ctx_t*
init_ctx()
{
    int status;

    ctx_t *ctx = static_cast<ctx_t*>(enif_alloc_resource(res_type, sizeof(*ctx)));

    if (ctx == NULL) {
        goto done;
    }

    ctx->queue = async_queue_create();
    ctx->topts = enif_thread_opts_create(const_cast<char*>("snappy_thread_opts"));

    status = enif_thread_create(const_cast<char*>("worker"),
        &ctx->tid, worker, ctx, ctx->topts);

    if (status != 0) {
        enif_release_resource(ctx);
        ctx = NULL;
        goto done;
    }

done:
    return ctx;
}

void
resource_dtor(ErlNifEnv*, void *obj)
{
    ctx_t  *ctx = static_cast<ctx_t*>(obj);
    task_t *task = init_empty_task(SHUTDOWN);
    void   *result = NULL;

    async_queue_push(ctx->queue, static_cast<void*>(task));
    enif_thread_join(ctx->tid, &result);
    async_queue_destroy(ctx->queue);
    enif_thread_opts_destroy(ctx->topts);
}

int
load(ErlNifEnv *env, void **, ERL_NIF_TERM)
{
    const char *mod = "erlang-snappy";
    const char *name = "nif_resource";

    ErlNifResourceFlags flags = static_cast<ErlNifResourceFlags>(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);

    res_type = enif_open_resource_type(env, mod, name, resource_dtor, flags, NULL);

    if (res_type == NULL) {
        return -1;
    }

    atom_ok = enif_make_atom(env, "ok");
    atom_error = enif_make_atom(env, "error");

    return 0;
}

ERL_NIF_TERM
snappy_create_ctx(ErlNifEnv *env, int, const ERL_NIF_TERM[])
{
    ERL_NIF_TERM  rv;
    ctx_t        *ctx;

    ctx = init_ctx();

    if (ctx == NULL) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create context",
                ERL_NIF_LATIN1));
    }

    rv = enif_make_resource(env, ctx);
    enif_release_resource(ctx);

    return enif_make_tuple2(env, atom_ok, rv);
}

ERL_NIF_TERM
snappy_compress_impl(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    ctx_t  *ctx;
    task_t *task;

    ErlNifPid pid;

    if (argc != 4) {
        return enif_make_badarg(env);
    }

    if (!enif_get_resource(env, argv[0], res_type,
            reinterpret_cast<void**>(&ctx))) {
        return enif_make_badarg(env);
    }

    if (!enif_is_ref(env, argv[1])) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Second arg. is not a reference",
                ERL_NIF_LATIN1));
    }

    if (!enif_get_local_pid(env, argv[2], &pid)) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Third arg. is not a pid of local process",
                ERL_NIF_LATIN1));
    }

    if (!(enif_is_binary(env, argv[3]) ||
          enif_is_list(env, argv[3]))) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Forth arg. is not a binary or a list",
                ERL_NIF_LATIN1));
    }

    task = init_task(COMPRESS, argv[1], pid, argv[3]);

    if (!task) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create a task",
                ERL_NIF_LATIN1));
    }

    async_queue_push(ctx->queue, static_cast<void*>(task));

    return atom_ok;
}

ERL_NIF_TERM
snappy_decompress_impl(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    ctx_t  *ctx;
    task_t *task;

    ErlNifPid pid;

    if (argc != 4) {
        return enif_make_badarg(env);
    }

    if (!enif_get_resource(env, argv[0], res_type,
            reinterpret_cast<void**>(&ctx))) {
        return enif_make_badarg(env);
    }

    if (!enif_is_ref(env, argv[1])) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Second arg. is not a reference",
                ERL_NIF_LATIN1));
    }

    if (!enif_get_local_pid(env, argv[2], &pid)) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Third arg. is not a pid of local process",
                ERL_NIF_LATIN1));
    }

    if (!(enif_is_binary(env, argv[3]) ||
          enif_is_list(env, argv[3]))) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Forth arg. is not a binary",
                ERL_NIF_LATIN1));
    }

    task = init_task(DECOMPRESS, argv[1], pid, argv[3]);

    if (!task) {
        return enif_make_tuple2(env, atom_error,
            enif_make_string(env, "Failed to create a task",
                ERL_NIF_LATIN1));
    }

    async_queue_push(ctx->queue, static_cast<void*>(task));

    return atom_ok;
}

static ErlNifFunc nif_funcs[] = {
    {"create_ctx", 0, snappy_create_ctx},
    {"compress_impl", 4, snappy_compress_impl},
    {"decompress_impl", 4, snappy_decompress_impl}
};

ERL_NIF_INIT(esnappy, nif_funcs, &load, NULL, NULL, NULL);

} // extern "C"
<|endoftext|>