<commit_before>#include "virtualserialdevice.h"
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

namespace SymbianUtils {

bool VirtualSerialDevice::isSequential() const
{
    return true;
}

VirtualSerialDevice::VirtualSerialDevice(const QString &aPortName, QObject *parent) :
    QIODevice(parent), portName(aPortName), lock(QMutex::NonRecursive), emittingBytesWritten(false), waiterForBytesWritten(NULL)
{
    platInit();
}

const QString& VirtualSerialDevice::getPortName() const
{
    return portName;
}

void VirtualSerialDevice::close()
{
    if (isOpen()) {
        Q_ASSERT(thread() == QThread::currentThread()); // My brain will explode otherwise
        flush();
        delete waiterForBytesWritten;
        waiterForBytesWritten = NULL;
        QMutexLocker locker(&lock);
        QIODevice::close();
        platClose();
    }
}

void VirtualSerialDevice::emitBytesWrittenIfNeeded(QMutexLocker& locker, qint64 len)
{
    if (waiterForBytesWritten) {
        waiterForBytesWritten->wakeAll();
    }
    if (!emittingBytesWritten) {
        emittingBytesWritten = true;
        locker.unlock();
        emit bytesWritten(len);
        locker.relock();
        emittingBytesWritten = false;
    }
}

} // namespace SymbianUtils
<commit_msg>Symbian: Serial device is not flushed when closed<commit_after>#include "virtualserialdevice.h"
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

namespace SymbianUtils {

bool VirtualSerialDevice::isSequential() const
{
    return true;
}

VirtualSerialDevice::VirtualSerialDevice(const QString &aPortName, QObject *parent) :
    QIODevice(parent), portName(aPortName), lock(QMutex::NonRecursive), emittingBytesWritten(false), waiterForBytesWritten(NULL)
{
    platInit();
}

const QString& VirtualSerialDevice::getPortName() const
{
    return portName;
}

void VirtualSerialDevice::close()
{
    if (isOpen()) {
        Q_ASSERT(thread() == QThread::currentThread()); // My brain will explode otherwise
        delete waiterForBytesWritten;
        waiterForBytesWritten = NULL;
        QMutexLocker locker(&lock);
        QIODevice::close();
        platClose();
    }
}

void VirtualSerialDevice::emitBytesWrittenIfNeeded(QMutexLocker& locker, qint64 len)
{
    if (waiterForBytesWritten) {
        waiterForBytesWritten->wakeAll();
    }
    if (!emittingBytesWritten) {
        emittingBytesWritten = true;
        locker.unlock();
        emit bytesWritten(len);
        locker.relock();
        emittingBytesWritten = false;
    }
}

} // namespace SymbianUtils
<|endoftext|>


<commit_before>#include <storm/platform/ogl/rendering_system_ogl.h>

#include <storm/platform/ogl/api_ogl.h>

#include <storm/platform/ogl/backbuffer_ogl.h>
#include <storm/platform/ogl/blending_technique_ogl.h>
#include <storm/platform/ogl/buffer_ogl.h>
#include <storm/platform/ogl/check_result_ogl.h>
#include <storm/platform/ogl/framebuffer_ogl.h>
#include <storm/platform/ogl/mesh_ogl.h>
#include <storm/platform/ogl/output_technique_ogl.h>
#include <storm/platform/ogl/rasterization_technique_ogl.h>
#include <storm/platform/ogl/shader_ogl.h>

#include <storm/rendering_window.h>

namespace storm {

ProgramPipelineHandleOgl::ProgramPipelineHandleOgl() {
    ::glGenProgramPipelines( 1, &_handle );
    checkResult( "::glGenProgramPipelines" );
}

ProgramPipelineHandleOgl::~ProgramPipelineHandleOgl() {
    ::glDeleteProgramPipelines( 1, &_handle );
}

void RenderingSystemOgl::initialize() {
    loadOpenGlApi();

    const OpenGlSupportStatus &supportStatus = getOpenGlSupportStatus();

    if( supportStatus.version < OpenGlVersion(4, 3) ) {
        if( !supportStatus.ARB_separate_shader_objects ) {
            throw SystemRequirementsNotMet() << "Video driver doesn't support "
                "required 'ARB_separate_shader_objects' OpenGL extension.";
        }
    }

    setVsyncEnabled( true );

    setRasterizationTechnique( RasterizationTechnique::getDefault() );
    setOutputTechnique( OutputTechnique::getDefault() );
    setBlendingTechnique( BlendingTechnique::getDefault() );

    const Dimensions dimensions =
        RenderingWindow::getInstance()->getDimensions();
    _clippingRectangle.width = _outputRectangle.width = dimensions.width;
    _clippingRectangle.height = _outputRectangle.height = dimensions.height;

    _programPipeline = std::make_shared<ProgramPipelineHandleOgl>();
    _vertexArray = std::make_shared<VertexArrayHandleOgl>();

    ::glBindProgramPipeline( *_programPipeline );
    checkResult( "::glBindProgramPipeline" );

    _backbuffer = std::make_shared<BackbufferOgl>();

    _primitiveRestartIndex = 0xffff;
    ::glPrimitiveRestartIndex( _primitiveRestartIndex );

    setBooleanGlState( GL_PRIMITIVE_RESTART, true );
}

void RenderingSystemOgl::beginFrameRendering() {
    return;
}

void RenderingSystemOgl::endFrameRendering() {
    return;
}

void RenderingSystemOgl::renderMesh( Mesh::Pointer mesh ) {
    storm_assert( mesh );

    auto nativeMesh = std::static_pointer_cast< MeshOgl >( mesh );

    ::glBindVertexArray( nativeMesh->getHandle() );
    checkResult( "::glBindVertexArray" );

    const auto &indexBufferDescription =
        mesh->getDescription().indexBuffer->getDescription();

    storm_assert(
        indexBufferDescription.elementSize == 2 ||
        indexBufferDescription.elementSize == 4 );

    const GLuint primitiveRestartIndex =
        (indexBufferDescription.elementSize == 2) ? 0xffff : 0xffffffff;

    if( _primitiveRestartIndex != primitiveRestartIndex ) {
        _primitiveRestartIndex = primitiveRestartIndex;
        ::glPrimitiveRestartIndex( _primitiveRestartIndex );
    }

    const GLenum primitiveTopology = nativeMesh->getPrimitiveTopology();
    const GLsizei indexCount =
        indexBufferDescription.size / indexBufferDescription.elementSize;
    const GLenum indexFormat = (indexBufferDescription.elementSize == 2) ?
        GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
    const GLvoid *indexOffset = nullptr;

    ::glDrawElements( primitiveTopology, indexCount, indexFormat, indexOffset );
    checkResult( "::glDrawElements" );
    return;
}

void RenderingSystemOgl::renderGenerated(
    unsigned int vertexCount, Mesh::PrimitiveTopology primitiveTopology )
{
    ::glBindVertexArray( *_vertexArray );
    checkResult( "::glBindVertexArray" );

    ::glDrawArrays(
        MeshOgl::convertPrimitiveTopology(primitiveTopology), 0, vertexCount );
    checkResult( "::glDrawArrays" );
}

void RenderingSystemOgl::setShader( Shader::Pointer shader ) {
    storm_assert( shader );

    const Shader::Type shaderType = shader->getType();

    if( getShader(shaderType) == shader )
        return;

    RenderingSystemCommon::setShader( shader );

    const auto nativeShader = std::static_pointer_cast< ShaderOgl >( shader );

    GLbitfield stage = 0;
    if( shaderType == Shader::Type::Vertex )
        stage = GL_VERTEX_SHADER_BIT;
    else if( shaderType == Shader::Type::Pixel )
        stage = GL_FRAGMENT_SHADER_BIT;
    else if( shaderType == Shader::Type::Geometry )
        stage = GL_GEOMETRY_SHADER_BIT;

    ::glUseProgramStages( *_programPipeline, stage, nativeShader->getHandle() );
    checkResult( "::glUseProgramStages" );

    nativeShader->install();
}

RasterizationTechnique::Pointer RenderingSystemOgl::getRasterizationTechnique() const {
    return _rasterizationTechnique;
}

OutputTechnique::Pointer RenderingSystemOgl::getOutputTechnique() const {
    return _outputTechnique;
}

BlendingTechnique::Pointer RenderingSystemOgl::getBlendingTechnique() const {
    return _blendingTechnique;
}

void RenderingSystemOgl::setRasterizationTechnique(
    RasterizationTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _rasterizationTechnique == technique ) return;

    auto nativeTechnique = std::static_pointer_cast< RasterizationTechniqueOgl >( technique );

    GLenum cullMode = nativeTechnique->getCullMode();
    GLenum fillMode = nativeTechnique->getFillMode();

    const bool cullingEnabled = (cullMode != GL_NONE);
    setBooleanGlState( GL_CULL_FACE, cullingEnabled );

    if( cullingEnabled ) {
        ::glFrontFace( GL_CW );
        checkResult( "::glFrontFace" );

        ::glCullFace( cullMode );
        checkResult( "::glCullFace" );
    }

    ::glPolygonMode( GL_FRONT_AND_BACK, fillMode );
    checkResult( "::glPolygonMode" );

    const auto &description = nativeTechnique->getDescription();

    setBooleanGlState( GL_SCISSOR_TEST, description.rectangleClippingEnabled );
    setBooleanGlState( GL_DEPTH_CLAMP, !description.depthClippingEnabled );

    ::glPolygonOffset( description.slopeScaleDepthBias, description.depthBias );
    checkResult( "::glPolygonOffset" );

    _rasterizationTechnique = technique;
    return;
}

void RenderingSystemOgl::setOutputTechnique(
    OutputTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _outputTechnique == technique ) return;

    auto nativeTechnique =
        std::static_pointer_cast< OutputTechniqueOgl >( technique );

    const auto &description = nativeTechnique->getNativeDescription();

    const auto &depthTest = description.depthTest;
    const auto &stencilTest = description.stencilTest;

    setBooleanGlState( GL_DEPTH_TEST, depthTest.enabled );
    setBooleanGlState( GL_STENCIL_TEST, stencilTest.enabled );

    if( depthTest.enabled ) {
        ::glDepthFunc( depthTest.passCondition );
        checkResult( "::glDepthFunc" );
    }

    if( stencilTest.enabled ) {
        ::glStencilOpSeparate(
            GL_FRONT,
            stencilTest.algorithmForFrontFaces.operationOnStencilTestFail,
            stencilTest.algorithmForFrontFaces.operationOnDepthTestFail,
            stencilTest.algorithmForFrontFaces.operationOnDepthTestPass );
        checkResult( "::glStencilOpSeparate" );

        ::glStencilOpSeparate(
            GL_BACK,
            stencilTest.algorithmForBackFaces.operationOnStencilTestFail,
            stencilTest.algorithmForBackFaces.operationOnDepthTestFail,
            stencilTest.algorithmForBackFaces.operationOnDepthTestPass );
        checkResult( "::glStencilOpSeparate" );

        ::glStencilFuncSeparate(
            GL_FRONT,
            stencilTest.algorithmForFrontFaces.passCondition,
            stencilTest.referenceValue,
            stencilTest.mask );
        checkResult( "::glStencilFuncSeparate" );

        ::glStencilFuncSeparate(
            GL_BACK,
            stencilTest.algorithmForBackFaces.passCondition,
            stencilTest.referenceValue,
            stencilTest.mask );
        checkResult( "::glStencilFuncSeparate" );
    }

    ::glDepthMask( description.writeDepthValues );
    checkResult( "::glDepthMask" );

    _outputTechnique = technique;
    return;
}

void RenderingSystemOgl::setBlendingTechnique(
    BlendingTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _blendingTechnique == technique ) return;

    auto nativeTechnique = std::static_pointer_cast< BlendingTechniqueOgl >( technique );

    const BlendingTechniqueOgl::EquationOgl colorEquation =
        nativeTechnique->getColorEquation();
    const BlendingTechniqueOgl::EquationOgl alphaEquation =
        nativeTechnique->getAlphaEquation();

    const bool blendingDisabled =
        colorEquation.operation == GL_FUNC_ADD &&
        alphaEquation.operation == GL_FUNC_ADD &&
        colorEquation.sourceFactor == GL_ONE &&
        alphaEquation.sourceFactor == GL_ONE &&
        colorEquation.destinationFactor == GL_ZERO &&
        alphaEquation.destinationFactor == GL_ZERO;
    const bool blendingEnabled = !blendingDisabled;

    setBooleanGlState( GL_BLEND, blendingEnabled );

    if( blendingEnabled ) {
        ::glBlendEquationSeparate(
            colorEquation.operation,
            alphaEquation.operation );
        checkResult( "::glBlendEquationSeparate" );

        ::glBlendFuncSeparate(
            colorEquation.sourceFactor,
            colorEquation.destinationFactor,
            alphaEquation.sourceFactor,
            alphaEquation.destinationFactor );
        checkResult( "::glBlendFuncSeparate" );
    }

    _blendingTechnique = technique;
}

const Rectangle& RenderingSystemOgl::getClippingRectangle() const {
    return _clippingRectangle;
}

const Rectangle& RenderingSystemOgl::getOutputRectangle() const {
    return _outputRectangle;
}

void RenderingSystemOgl::setClippingRectangle( const Rectangle &rectangle ) {
    ::glScissor(
        rectangle.x,
        rectangle.y,
        rectangle.width,
        rectangle.height );
    checkResult( "::glScissor" );
    _clippingRectangle = rectangle;
}

void RenderingSystemOgl::setOutputRectangle( const Rectangle &rectangle ) {
    ::glViewport(
        rectangle.x,
        rectangle.y,
        rectangle.width,
        rectangle.height );
    checkResult( "::glViewport" );
    _outputRectangle = rectangle;
}

Framebuffer::Pointer RenderingSystemOgl::getFramebuffer() const {
    return _framebuffer;
}

void RenderingSystemOgl::setFramebuffer(
    Framebuffer::Pointer framebuffer, bool preserveOutputRectangle )
{
    if( _framebuffer == framebuffer )
        return;

    auto nativeFramebuffer =
        std::static_pointer_cast< FramebufferOgl >( framebuffer );

    const GLint framebufferHandle =
        nativeFramebuffer ? nativeFramebuffer->getHandle() : 0;

    ::glBindFramebuffer( GL_FRAMEBUFFER, framebufferHandle );
    checkResult( "::glBindFramebuffer" );

    if( !preserveOutputRectangle ) {
        unsigned int width;
        unsigned int height;

        if( framebuffer ) {
            const Framebuffer::Buffer &buffer =
                framebuffer->getDescription().buffers.front();

            const Texture::MipLevelDimensions mipLevelDimensions =
                buffer.texture->getMipLevelDimensions( buffer.mipLevel );
            width = mipLevelDimensions.width;
            height = mipLevelDimensions.height;
        } else {
            const Dimensions windowDimensions =
                RenderingWindow::getInstance()->getDimensions();
            width = windowDimensions.width;
            height = windowDimensions.height;
        }

        setOutputRectangle( {0, 0, width, height} );
    }

    _framebuffer = framebuffer;
}

void RenderingSystemOgl::clearColorBuffer( const Color &color ) {
    ::glClearColor( color.r, color.g, color.b, color.a );
    checkResult( "::glClearColor" );

    ::glClear( GL_COLOR_BUFFER_BIT );
    checkResult( "::glClear" );
    return;
}

void RenderingSystemOgl::clearDepthBuffer( float depth ) {
    const bool depthWritingEnabled =
        _outputTechnique->getDescription().writeDepthValues;

    if( !depthWritingEnabled ) {
        // Depth buffer writing must be temporarily enabled

        ::glDepthMask( GL_TRUE );
        checkResult( "::glDepthMask" );
    }

    ::glClearDepth( depth );
    checkResult( "::glClearDepth" );

    ::glClear( GL_DEPTH_BUFFER_BIT );
    checkResult( "::glClear" );

    if( !depthWritingEnabled ) {
        // Restore previous value

        ::glDepthMask( GL_FALSE );
        checkResult( "::glDepthMask" );
    }
    return;
}

void RenderingSystemOgl::clearStencilBuffer( unsigned int stencil ) {
    ::glClearStencil( stencil );
    checkResult( "::glClearStencil" );

    ::glClear( GL_STENCIL_BUFFER_BIT );
    checkResult( "::glClear" );
    return;
}

Backbuffer::Pointer RenderingSystemOgl::getBackbuffer() const {
    return _backbuffer;
}

std::string RenderingSystemOgl::getDebugMessageLog() const {
    std::string log;

    auto getIntegerParameter = []( GLenum parameter ) {
        GLint parameterValue = 0;
        ::glGetIntegerv( parameter, &parameterValue );
        checkResult( "::glGetIntegerv" );
        return parameterValue;
    };

    if( getOpenGlSupportStatus().KHR_debug ) {
        GLint messageCount = getIntegerParameter( GL_DEBUG_LOGGED_MESSAGES );
        while( messageCount-- ) {
            std::string message(
                getIntegerParameter(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH), 0 );

            ::glGetDebugMessageLog(
                /* messageCount = */ 1,
                message.size(),
                nullptr,
                nullptr,
                nullptr,
                nullptr,
                nullptr,
                &message[0] );
            checkResult( "::glGetDebugMessageLog" );

            // Remove null character.
            message.erase( message.size() - 1 );

            log += message + '\n';
        }
    }
    return log;
}

void RenderingSystemOgl::installOpenGlContext() {
    // OpenGL context is installed when the rendering system is being created
    RenderingSystem::getInstance();
}

void RenderingSystemOgl::setBooleanGlState( GLenum state, bool value ) {
    if( value ) {
        ::glEnable( state );
        checkResult( "::glEnable" );
    } else {
        ::glDisable( state );
        checkResult( "::glDisable" );
    }
}

}
<commit_msg>Limited separate blending usage<commit_after>#include <storm/platform/ogl/rendering_system_ogl.h>

#include <storm/platform/ogl/api_ogl.h>

#include <storm/platform/ogl/backbuffer_ogl.h>
#include <storm/platform/ogl/blending_technique_ogl.h>
#include <storm/platform/ogl/buffer_ogl.h>
#include <storm/platform/ogl/check_result_ogl.h>
#include <storm/platform/ogl/framebuffer_ogl.h>
#include <storm/platform/ogl/mesh_ogl.h>
#include <storm/platform/ogl/output_technique_ogl.h>
#include <storm/platform/ogl/rasterization_technique_ogl.h>
#include <storm/platform/ogl/shader_ogl.h>

#include <storm/rendering_window.h>

namespace storm {

ProgramPipelineHandleOgl::ProgramPipelineHandleOgl() {
    ::glGenProgramPipelines( 1, &_handle );
    checkResult( "::glGenProgramPipelines" );
}

ProgramPipelineHandleOgl::~ProgramPipelineHandleOgl() {
    ::glDeleteProgramPipelines( 1, &_handle );
}

void RenderingSystemOgl::initialize() {
    loadOpenGlApi();

    const OpenGlSupportStatus &supportStatus = getOpenGlSupportStatus();

    if( supportStatus.version < OpenGlVersion(4, 3) ) {
        if( !supportStatus.ARB_separate_shader_objects ) {
            throw SystemRequirementsNotMet() << "Video driver doesn't support "
                "required 'ARB_separate_shader_objects' OpenGL extension.";
        }
    }

    setVsyncEnabled( true );

    setRasterizationTechnique( RasterizationTechnique::getDefault() );
    setOutputTechnique( OutputTechnique::getDefault() );
    setBlendingTechnique( BlendingTechnique::getDefault() );

    const Dimensions dimensions =
        RenderingWindow::getInstance()->getDimensions();
    _clippingRectangle.width = _outputRectangle.width = dimensions.width;
    _clippingRectangle.height = _outputRectangle.height = dimensions.height;

    _programPipeline = std::make_shared<ProgramPipelineHandleOgl>();
    _vertexArray = std::make_shared<VertexArrayHandleOgl>();

    ::glBindProgramPipeline( *_programPipeline );
    checkResult( "::glBindProgramPipeline" );

    _backbuffer = std::make_shared<BackbufferOgl>();

    _primitiveRestartIndex = 0xffff;
    ::glPrimitiveRestartIndex( _primitiveRestartIndex );

    setBooleanGlState( GL_PRIMITIVE_RESTART, true );
}

void RenderingSystemOgl::beginFrameRendering() {
    return;
}

void RenderingSystemOgl::endFrameRendering() {
    return;
}

void RenderingSystemOgl::renderMesh( Mesh::Pointer mesh ) {
    storm_assert( mesh );

    auto nativeMesh = std::static_pointer_cast< MeshOgl >( mesh );

    ::glBindVertexArray( nativeMesh->getHandle() );
    checkResult( "::glBindVertexArray" );

    const auto &indexBufferDescription =
        mesh->getDescription().indexBuffer->getDescription();

    storm_assert(
        indexBufferDescription.elementSize == 2 ||
        indexBufferDescription.elementSize == 4 );

    const GLuint primitiveRestartIndex =
        (indexBufferDescription.elementSize == 2) ? 0xffff : 0xffffffff;

    if( _primitiveRestartIndex != primitiveRestartIndex ) {
        _primitiveRestartIndex = primitiveRestartIndex;
        ::glPrimitiveRestartIndex( _primitiveRestartIndex );
    }

    const GLenum primitiveTopology = nativeMesh->getPrimitiveTopology();
    const GLsizei indexCount =
        indexBufferDescription.size / indexBufferDescription.elementSize;
    const GLenum indexFormat = (indexBufferDescription.elementSize == 2) ?
        GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
    const GLvoid *indexOffset = nullptr;

    ::glDrawElements( primitiveTopology, indexCount, indexFormat, indexOffset );
    checkResult( "::glDrawElements" );
    return;
}

void RenderingSystemOgl::renderGenerated(
    unsigned int vertexCount, Mesh::PrimitiveTopology primitiveTopology )
{
    ::glBindVertexArray( *_vertexArray );
    checkResult( "::glBindVertexArray" );

    ::glDrawArrays(
        MeshOgl::convertPrimitiveTopology(primitiveTopology), 0, vertexCount );
    checkResult( "::glDrawArrays" );
}

void RenderingSystemOgl::setShader( Shader::Pointer shader ) {
    storm_assert( shader );

    const Shader::Type shaderType = shader->getType();

    if( getShader(shaderType) == shader )
        return;

    RenderingSystemCommon::setShader( shader );

    const auto nativeShader = std::static_pointer_cast< ShaderOgl >( shader );

    GLbitfield stage = 0;
    if( shaderType == Shader::Type::Vertex )
        stage = GL_VERTEX_SHADER_BIT;
    else if( shaderType == Shader::Type::Pixel )
        stage = GL_FRAGMENT_SHADER_BIT;
    else if( shaderType == Shader::Type::Geometry )
        stage = GL_GEOMETRY_SHADER_BIT;

    ::glUseProgramStages( *_programPipeline, stage, nativeShader->getHandle() );
    checkResult( "::glUseProgramStages" );

    nativeShader->install();
}

RasterizationTechnique::Pointer RenderingSystemOgl::getRasterizationTechnique() const {
    return _rasterizationTechnique;
}

OutputTechnique::Pointer RenderingSystemOgl::getOutputTechnique() const {
    return _outputTechnique;
}

BlendingTechnique::Pointer RenderingSystemOgl::getBlendingTechnique() const {
    return _blendingTechnique;
}

void RenderingSystemOgl::setRasterizationTechnique(
    RasterizationTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _rasterizationTechnique == technique ) return;

    auto nativeTechnique = std::static_pointer_cast< RasterizationTechniqueOgl >( technique );

    GLenum cullMode = nativeTechnique->getCullMode();
    GLenum fillMode = nativeTechnique->getFillMode();

    const bool cullingEnabled = (cullMode != GL_NONE);
    setBooleanGlState( GL_CULL_FACE, cullingEnabled );

    if( cullingEnabled ) {
        ::glFrontFace( GL_CW );
        checkResult( "::glFrontFace" );

        ::glCullFace( cullMode );
        checkResult( "::glCullFace" );
    }

    ::glPolygonMode( GL_FRONT_AND_BACK, fillMode );
    checkResult( "::glPolygonMode" );

    const auto &description = nativeTechnique->getDescription();

    setBooleanGlState( GL_SCISSOR_TEST, description.rectangleClippingEnabled );
    setBooleanGlState( GL_DEPTH_CLAMP, !description.depthClippingEnabled );

    ::glPolygonOffset( description.slopeScaleDepthBias, description.depthBias );
    checkResult( "::glPolygonOffset" );

    _rasterizationTechnique = technique;
    return;
}

void RenderingSystemOgl::setOutputTechnique(
    OutputTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _outputTechnique == technique ) return;

    auto nativeTechnique =
        std::static_pointer_cast< OutputTechniqueOgl >( technique );

    const auto &description = nativeTechnique->getNativeDescription();

    const auto &depthTest = description.depthTest;
    const auto &stencilTest = description.stencilTest;

    setBooleanGlState( GL_DEPTH_TEST, depthTest.enabled );
    setBooleanGlState( GL_STENCIL_TEST, stencilTest.enabled );

    if( depthTest.enabled ) {
        ::glDepthFunc( depthTest.passCondition );
        checkResult( "::glDepthFunc" );
    }

    if( stencilTest.enabled ) {
        ::glStencilOpSeparate(
            GL_FRONT,
            stencilTest.algorithmForFrontFaces.operationOnStencilTestFail,
            stencilTest.algorithmForFrontFaces.operationOnDepthTestFail,
            stencilTest.algorithmForFrontFaces.operationOnDepthTestPass );
        checkResult( "::glStencilOpSeparate" );

        ::glStencilOpSeparate(
            GL_BACK,
            stencilTest.algorithmForBackFaces.operationOnStencilTestFail,
            stencilTest.algorithmForBackFaces.operationOnDepthTestFail,
            stencilTest.algorithmForBackFaces.operationOnDepthTestPass );
        checkResult( "::glStencilOpSeparate" );

        ::glStencilFuncSeparate(
            GL_FRONT,
            stencilTest.algorithmForFrontFaces.passCondition,
            stencilTest.referenceValue,
            stencilTest.mask );
        checkResult( "::glStencilFuncSeparate" );

        ::glStencilFuncSeparate(
            GL_BACK,
            stencilTest.algorithmForBackFaces.passCondition,
            stencilTest.referenceValue,
            stencilTest.mask );
        checkResult( "::glStencilFuncSeparate" );
    }

    ::glDepthMask( description.writeDepthValues );
    checkResult( "::glDepthMask" );

    _outputTechnique = technique;
    return;
}

void RenderingSystemOgl::setBlendingTechnique(
    BlendingTechnique::Pointer technique )
{
    storm_assert( technique );
    if( _blendingTechnique == technique ) return;

    auto nativeTechnique = std::static_pointer_cast< BlendingTechniqueOgl >( technique );

    const BlendingTechniqueOgl::EquationOgl colorEquation =
        nativeTechnique->getColorEquation();
    const BlendingTechniqueOgl::EquationOgl alphaEquation =
        nativeTechnique->getAlphaEquation();

    const bool blendingDisabled =
        colorEquation.operation == GL_FUNC_ADD &&
        alphaEquation.operation == GL_FUNC_ADD &&
        colorEquation.sourceFactor == GL_ONE &&
        alphaEquation.sourceFactor == GL_ONE &&
        colorEquation.destinationFactor == GL_ZERO &&
        alphaEquation.destinationFactor == GL_ZERO;
    const bool blendingEnabled = !blendingDisabled;

    setBooleanGlState( GL_BLEND, blendingEnabled );

    if( blendingEnabled ) {
        if( colorEquation.operation == alphaEquation.operation ) {
            ::glBlendEquation( colorEquation.operation );
            checkResult( "::glBlendEquation" );
        } else {
            ::glBlendEquationSeparate(
                colorEquation.operation,
                alphaEquation.operation );
            checkResult( "::glBlendEquationSeparate" );
        }

        if( colorEquation.sourceFactor == alphaEquation.sourceFactor &&
            colorEquation.destinationFactor == alphaEquation.destinationFactor )
        {
            ::glBlendFunc(
                colorEquation.sourceFactor,
                colorEquation.destinationFactor );
            checkResult( "::glBlendFunc" );
        } else {
            ::glBlendFuncSeparate(
                colorEquation.sourceFactor,
                colorEquation.destinationFactor,
                alphaEquation.sourceFactor,
                alphaEquation.destinationFactor );
            checkResult( "::glBlendFuncSeparate" );
        }
    }

    _blendingTechnique = technique;
}

const Rectangle& RenderingSystemOgl::getClippingRectangle() const {
    return _clippingRectangle;
}

const Rectangle& RenderingSystemOgl::getOutputRectangle() const {
    return _outputRectangle;
}

void RenderingSystemOgl::setClippingRectangle( const Rectangle &rectangle ) {
    ::glScissor(
        rectangle.x,
        rectangle.y,
        rectangle.width,
        rectangle.height );
    checkResult( "::glScissor" );
    _clippingRectangle = rectangle;
}

void RenderingSystemOgl::setOutputRectangle( const Rectangle &rectangle ) {
    ::glViewport(
        rectangle.x,
        rectangle.y,
        rectangle.width,
        rectangle.height );
    checkResult( "::glViewport" );
    _outputRectangle = rectangle;
}

Framebuffer::Pointer RenderingSystemOgl::getFramebuffer() const {
    return _framebuffer;
}

void RenderingSystemOgl::setFramebuffer(
    Framebuffer::Pointer framebuffer, bool preserveOutputRectangle )
{
    if( _framebuffer == framebuffer )
        return;

    auto nativeFramebuffer =
        std::static_pointer_cast< FramebufferOgl >( framebuffer );

    const GLint framebufferHandle =
        nativeFramebuffer ? nativeFramebuffer->getHandle() : 0;

    ::glBindFramebuffer( GL_FRAMEBUFFER, framebufferHandle );
    checkResult( "::glBindFramebuffer" );

    if( !preserveOutputRectangle ) {
        unsigned int width;
        unsigned int height;

        if( framebuffer ) {
            const Framebuffer::Buffer &buffer =
                framebuffer->getDescription().buffers.front();

            const Texture::MipLevelDimensions mipLevelDimensions =
                buffer.texture->getMipLevelDimensions( buffer.mipLevel );
            width = mipLevelDimensions.width;
            height = mipLevelDimensions.height;
        } else {
            const Dimensions windowDimensions =
                RenderingWindow::getInstance()->getDimensions();
            width = windowDimensions.width;
            height = windowDimensions.height;
        }

        setOutputRectangle( {0, 0, width, height} );
    }

    _framebuffer = framebuffer;
}

void RenderingSystemOgl::clearColorBuffer( const Color &color ) {
    ::glClearColor( color.r, color.g, color.b, color.a );
    checkResult( "::glClearColor" );

    ::glClear( GL_COLOR_BUFFER_BIT );
    checkResult( "::glClear" );
    return;
}

void RenderingSystemOgl::clearDepthBuffer( float depth ) {
    const bool depthWritingEnabled =
        _outputTechnique->getDescription().writeDepthValues;

    if( !depthWritingEnabled ) {
        // Depth buffer writing must be temporarily enabled

        ::glDepthMask( GL_TRUE );
        checkResult( "::glDepthMask" );
    }

    ::glClearDepth( depth );
    checkResult( "::glClearDepth" );

    ::glClear( GL_DEPTH_BUFFER_BIT );
    checkResult( "::glClear" );

    if( !depthWritingEnabled ) {
        // Restore previous value

        ::glDepthMask( GL_FALSE );
        checkResult( "::glDepthMask" );
    }
    return;
}

void RenderingSystemOgl::clearStencilBuffer( unsigned int stencil ) {
    ::glClearStencil( stencil );
    checkResult( "::glClearStencil" );

    ::glClear( GL_STENCIL_BUFFER_BIT );
    checkResult( "::glClear" );
    return;
}

Backbuffer::Pointer RenderingSystemOgl::getBackbuffer() const {
    return _backbuffer;
}

std::string RenderingSystemOgl::getDebugMessageLog() const {
    std::string log;

    auto getIntegerParameter = []( GLenum parameter ) {
        GLint parameterValue = 0;
        ::glGetIntegerv( parameter, &parameterValue );
        checkResult( "::glGetIntegerv" );
        return parameterValue;
    };

    if( getOpenGlSupportStatus().KHR_debug ) {
        GLint messageCount = getIntegerParameter( GL_DEBUG_LOGGED_MESSAGES );
        while( messageCount-- ) {
            std::string message(
                getIntegerParameter(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH), 0 );

            ::glGetDebugMessageLog(
                /* messageCount = */ 1,
                message.size(),
                nullptr,
                nullptr,
                nullptr,
                nullptr,
                nullptr,
                &message[0] );
            checkResult( "::glGetDebugMessageLog" );

            // Remove null character.
            message.erase( message.size() - 1 );

            log += message + '\n';
        }
    }
    return log;
}

void RenderingSystemOgl::installOpenGlContext() {
    // OpenGL context is installed when the rendering system is being created
    RenderingSystem::getInstance();
}

void RenderingSystemOgl::setBooleanGlState( GLenum state, bool value ) {
    if( value ) {
        ::glEnable( state );
        checkResult( "::glEnable" );
    } else {
        ::glDisable( state );
        checkResult( "::glDisable" );
    }
}

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2015, Dimitri Diakopoulos All rights reserved.

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

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

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

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

#include "WavPackDecoder.h"
#include "wavpack.h"

using namespace nqr;

class WavPackInternal
{

public:

    WavPackInternal(AudioData * d, const std::string path) : d(d)
    {
        char errorStr[128];
        context = WavpackOpenFileInput(path.c_str(), errorStr, OPEN_WVC | OPEN_NORMALIZE, 0);

        if (!context)
        {
            throw std::runtime_error("Not a WavPack file");
        }

        auto bitdepth = WavpackGetBitsPerSample(context);

        d->sampleRate = WavpackGetSampleRate(context);
        d->channelCount = WavpackGetNumChannels(context);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = d->channelCount * bitdepth;

        //@todo support channel masks
        // WavpackGetChannelMask

        auto totalSamples = size_t(getTotalSamples());

        int mode = WavpackGetMode(context);
        bool isFloatingPoint = (MODE_FLOAT & mode);

        d->sourceFormat = MakeFormatForBits(bitdepth, isFloatingPoint, false);

        /* From the docs:
            "... required memory at "buffer" is 4 * samples * num_channels bytes. The
            audio data is returned right-justified in 32-bit longs in the endian
            mode native to the executing processor."
        */
        d->samples.resize(totalSamples * d->channelCount);

        if (!isFloatingPoint)
            internalBuffer.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");

        // Next, process internal buffer into the user-visible samples array
        if (!isFloatingPoint)
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples * d->channelCount, d->sourceFormat);

    }

    ~WavPackInternal()
    {
        WavpackCloseFile(context);
    }

    size_t readInternal(size_t requestedFrameCount, size_t frameOffset = 0)
    {
        size_t framesRemaining = requestedFrameCount;
        size_t totalFramesRead = 0;

        // int frameSize = d->channelCount * WavpackGetBitsPerSample(context);

        // The samples returned are handled differently based on the file's mode
        int mode = WavpackGetMode(context);

        while (0 < framesRemaining)
        {
            uint32_t framesRead = -1;

            if (MODE_FLOAT & mode)
            {
                // Since it's float, we can decode directly into our buffer as a huge blob
                framesRead = WavpackUnpackSamples(context, reinterpret_cast<int32_t*>(&d->samples.data()[0]), uint32_t(d->samples.size() / d->channelCount));
            }

            else if(MODE_LOSSLESS & mode)
            {
                // Lossless files will be handed off as integers
                framesRead = WavpackUnpackSamples(context, internalBuffer.data(), uint32_t(internalBuffer.size() / d->channelCount));
            }

            // EOF
            //if (framesRead == 0)
            //    break;

            totalFramesRead += framesRead;
            framesRemaining -= framesRead;
        }

        return totalFramesRead;
    }

private:

    NO_MOVE(WavPackInternal);

    //WavpackStreamReader streamReader; //@todo: streaming support

    WavpackContext * context; //@todo unique_ptr

    AudioData * d;

    std::vector<int32_t> internalBuffer;

    inline int64_t getTotalSamples() const { return WavpackGetNumSamples(context); }
    inline int64_t getLengthInSeconds() const { return getTotalSamples() / WavpackGetSampleRate(context); }

};

//////////////////////
// Public Interface //
//////////////////////

void WavPackDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    WavPackInternal decoder(data, path);
}

void WavPackDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    throw LoadBufferNotImplEx();
}

std::vector<std::string> WavPackDecoder::GetSupportedFileExtensions()
{
    return {"wv"};
}
<commit_msg>Add buffer wabpack decoder<commit_after>/*
Copyright (c) 2015, Dimitri Diakopoulos All rights reserved.

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

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

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

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

#include "WavPackDecoder.h"
#include "wavpack.h"
#include <string.h>

using namespace nqr;

class WavPackInternal
{

public:

    WavPackInternal(AudioData * d, const std::string path) : d(d)
    {
        char errorStr[128];
        context = WavpackOpenFileInput(path.c_str(), errorStr, OPEN_WVC | OPEN_NORMALIZE, 0);

        if (!context)
        {
            throw std::runtime_error("Not a WavPack file");
        }

        auto bitdepth = WavpackGetBitsPerSample(context);

        d->sampleRate = WavpackGetSampleRate(context);
        d->channelCount = WavpackGetNumChannels(context);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = d->channelCount * bitdepth;

        //@todo support channel masks
        // WavpackGetChannelMask

        auto totalSamples = size_t(getTotalSamples());

        int mode = WavpackGetMode(context);
        bool isFloatingPoint = (MODE_FLOAT & mode);

        d->sourceFormat = MakeFormatForBits(bitdepth, isFloatingPoint, false);

        /* From the docs:
            "... required memory at "buffer" is 4 * samples * num_channels bytes. The
            audio data is returned right-justified in 32-bit longs in the endian
            mode native to the executing processor."
        */
        d->samples.resize(totalSamples * d->channelCount);

        if (!isFloatingPoint)
            internalBuffer.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");

        // Next, process internal buffer into the user-visible samples array
        if (!isFloatingPoint)
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples * d->channelCount, d->sourceFormat);

    }

    WavPackInternal(AudioData * d, const std::vector<uint8_t> & memory) : d(d), data(std::move(memory)), dataPos(0)
    {
        WavpackStreamReader64 reader = {
          read_bytes,
          write_bytes,
          get_pos,
          set_pos_abs,
          set_pos_rel,
          push_back_byte,
          get_length,
          can_seek,
          truncate_here,
          close,
        };
        char errorStr[128];
        context = WavpackOpenFileInputEx64 (&reader, this, nullptr, errorStr, OPEN_WVC | OPEN_NORMALIZE, 0);

        if (!context)
        {
            throw std::runtime_error("Not a WavPack file");
        }

        auto bitdepth = WavpackGetBitsPerSample(context);

        d->sampleRate = WavpackGetSampleRate(context);
        d->channelCount = WavpackGetNumChannels(context);
        d->lengthSeconds = double(getLengthInSeconds());
        d->frameSize = d->channelCount * bitdepth;

        //@todo support channel masks
        // WavpackGetChannelMask

        auto totalSamples = size_t(getTotalSamples());

        int mode = WavpackGetMode(context);
        bool isFloatingPoint = (MODE_FLOAT & mode);

        d->sourceFormat = MakeFormatForBits(bitdepth, isFloatingPoint, false);

        /* From the docs:
            "... required memory at "buffer" is 4 * samples * num_channels bytes. The
            audio data is returned right-justified in 32-bit longs in the endian
            mode native to the executing processor."
        */
        d->samples.resize(totalSamples * d->channelCount);

        if (!isFloatingPoint)
            internalBuffer.resize(totalSamples * d->channelCount);

        if (!readInternal(totalSamples))
            throw std::runtime_error("could not read any data");

        // Next, process internal buffer into the user-visible samples array
        if (!isFloatingPoint)
            ConvertToFloat32(d->samples.data(), internalBuffer.data(), totalSamples * d->channelCount, d->sourceFormat);

    }

    ~WavPackInternal()
    {
        WavpackCloseFile(context);
    }

    size_t readInternal(size_t requestedFrameCount, size_t frameOffset = 0)
    {
        size_t framesRemaining = requestedFrameCount;
        size_t totalFramesRead = 0;

        // int frameSize = d->channelCount * WavpackGetBitsPerSample(context);

        // The samples returned are handled differently based on the file's mode
        int mode = WavpackGetMode(context);

        while (0 < framesRemaining)
        {
            uint32_t framesRead = -1;

            if (MODE_FLOAT & mode)
            {
                // Since it's float, we can decode directly into our buffer as a huge blob
                framesRead = WavpackUnpackSamples(context, reinterpret_cast<int32_t*>(&d->samples.data()[0]), uint32_t(d->samples.size() / d->channelCount));
            }

            else if(MODE_LOSSLESS & mode)
            {
                // Lossless files will be handed off as integers
                framesRead = WavpackUnpackSamples(context, internalBuffer.data(), uint32_t(internalBuffer.size() / d->channelCount));
            }

            // EOF
            //if (framesRead == 0)
            //    break;

            totalFramesRead += framesRead;
            framesRemaining -= framesRead;
        }

        return totalFramesRead;
    }

    static int32_t read_bytes(void *id, void *data, int32_t bcount) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        int32_t readLength = std::min<size_t>(bcount, decoder->data.size() - decoder->dataPos);
        if (readLength > 0) {
          memcpy(data, decoder->data.data(), readLength);
          decoder->dataPos += readLength;
          return readLength;
        } else {
          return 0;
        }
      } else {
        return 0;
      }
    }
    static int32_t write_bytes(void *id, void *data, int32_t bcount) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        int32_t writeLength = std::min<size_t>(bcount, decoder->data.size() - decoder->dataPos);
        if (writeLength > 0) {
          memcpy(decoder->data.data(), data, writeLength);
          decoder->dataPos += writeLength;
          return writeLength;
        } else {
          return 0;
        }
      } else {
        return 0;
      }
    }
    static int64_t get_pos(void *id) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        return decoder->dataPos;
      } else {
        return 0;
      }
    }
    static int set_pos_abs(void *id, int64_t pos) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        size_t newPos = std::min<size_t>(pos, decoder->data.size());
        decoder->dataPos = newPos;
        return newPos;
      } else {
        return 0;
      }
    }
    static int set_pos_rel(void *id, int64_t delta, int mode) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        size_t newPos = 0;
        if (mode == SEEK_SET) {
          newPos = delta;
        } else if (mode == SEEK_CUR) {
          newPos = decoder->dataPos + delta;
        } else if (mode == SEEK_END) {
          newPos = decoder->data.size() + delta;
        }
        newPos = std::min<size_t>(newPos, decoder->data.size());
        decoder->dataPos = newPos;
        return newPos;
      } else {
        return 0;
      }
    }
    static int push_back_byte(void *id, int c) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        decoder->dataPos--;
        decoder->data[decoder->dataPos] = c;
        return 1;
      } else {
        return 0;
      }
    }
    static int64_t get_length(void *id) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        return decoder->data.size();
      } else {
        return 0;
      }
    }
    static int can_seek(void *id) {
      if (id != nullptr) {
        return 1;
      } else {
        return 0;
      }
    }
    static int truncate_here(void *id) {
      if (id != nullptr) {
        WavPackInternal *decoder = (WavPackInternal *)id;
        decoder->data.resize(decoder->dataPos);
        return 1;
      } else {
        return 0;
      }
    }
    static int close(void *id) {
      if (id != nullptr) {
        return 1;
      } else {
        return 0;
      }
    }

private:

    NO_MOVE(WavPackInternal);

    //WavpackStreamReader streamReader; //@todo: streaming support

    WavpackContext * context; //@todo unique_ptr

    AudioData * d;
    std::vector<uint8_t> data;
    size_t dataPos;

    std::vector<int32_t> internalBuffer;

    inline int64_t getTotalSamples() const { return WavpackGetNumSamples(context); }
    inline int64_t getLengthInSeconds() const { return getTotalSamples() / WavpackGetSampleRate(context); }

};

//////////////////////
// Public Interface //
//////////////////////

void WavPackDecoder::LoadFromPath(AudioData * data, const std::string & path)
{
    WavPackInternal decoder(data, path);
}

void WavPackDecoder::LoadFromBuffer(AudioData * data, const std::vector<uint8_t> & memory)
{
    WavPackInternal decoder(data, memory);
}

std::vector<std::string> WavPackDecoder::GetSupportedFileExtensions()
{
    return {"wv"};
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008-2015 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include <queso/InterpolationSurrogateBase.h>

// QUESO
#include <queso/GslVector.h>
#include <queso/GslMatrix.h>
#include <queso/VectorSpace.h>

// C++
#include <sstream>

namespace QUESO
{
  template<class V, class M>
  InterpolationSurrogateBase<V,M>::InterpolationSurrogateBase(const BoxSubset<V,M> & domain,
                                                              const std::vector<unsigned int>& n_points,
                                                              const std::vector<double>& values)
    : SurrogateBase<V,M>(),
    m_domain(domain),
    m_n_points(n_points),
    m_values(values)
    {
      // This checks that the dimension of n_points and the domain are consistent
      this->check_dim_consistency();
    }

  template<class V, class M>
  unsigned int InterpolationSurrogateBase<V,M>::coordToGlobal( const std::vector<unsigned int>& coord_indices,
                                                               const std::vector<unsigned int>& n_points ) const
  {
    // Make sure dimension is consistent between inputs
    queso_assert_equal_to( coord_indices.size(), n_points.size() );

    // Make sure dimension is consisent with parameter space
    queso_assert_equal_to( coord_indices.size(), this->m_domain.vectorSpace().dimGlobal() );

    unsigned int dim = this->m_domain.vectorSpace().dimGlobal();

    /* Mapping is: i + j*n_i + k*n_i*n_j + l*n_i*n_j*n_k + ...
       Initialize global_index to "i".
       Then loop and build up each term.*/
    unsigned int global_index = coord_indices[0];

    for( unsigned int d = 1; d < dim; d++ )
      {
        // Accumulate the current term
        unsigned int idx = coord_indices[d];
        unsigned int local_d = d-1;
        do
          {
            idx *= n_points[local_d];
            local_d -= 1;
          } while( local_d >= 0 );

        global_index += idx;
      }

    return global_index;
  }

  template<class V, class M>
  void InterpolationSurrogateBase<V,M>::check_dim_consistency() const
  {
    if( this->m_domain.vectorSpace().dimGlobal() != this->m_n_points.size() )
      {
        std::stringstream vspace_dim;
        vspace_dim << this->m_domain.vectorSpace().dimGlobal();

        std::stringstream n_points_dim;
        n_points_dim << this->m_n_points.size();

        std::string error = "ERROR: Mismatch between dimension of parameter space and number of points\n.";
        error += "        domain dimension = " + vspace_dim.str() + "\n";
        error += "        points dimension = " + n_points_dim.str() + "\n";

        queso_error_msg(error);
      }
  }

  template<class V, class M>
  double InterpolationSurrogateBase<V,M>::spacing( unsigned int dim ) const
  {
    unsigned int n_intervals = this->m_n_points[dim]-1;
    double x_min = this->x_min(dim);
    double x_max = this->x_max(dim);

    return (x_max-x_min)/n_intervals;
  }

} // end namespace QUESO

// Instantiate
template class QUESO::InterpolationSurrogateBase<QUESO::GslVector,QUESO::GslMatrix>;
<commit_msg>Use helper functions<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008-2015 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include <queso/InterpolationSurrogateBase.h>

// QUESO
#include <queso/GslVector.h>
#include <queso/GslMatrix.h>

// C++
#include <sstream>

namespace QUESO
{
  template<class V, class M>
  InterpolationSurrogateBase<V,M>::InterpolationSurrogateBase(const BoxSubset<V,M> & domain,
                                                              const std::vector<unsigned int>& n_points,
                                                              const std::vector<double>& values)
    : SurrogateBase<V,M>(),
    m_domain(domain),
    m_n_points(n_points),
    m_values(values)
    {
      // This checks that the dimension of n_points and the domain are consistent
      this->check_dim_consistency();
    }

  template<class V, class M>
  unsigned int InterpolationSurrogateBase<V,M>::coordToGlobal( const std::vector<unsigned int>& coord_indices,
                                                               const std::vector<unsigned int>& n_points ) const
  {
    // Make sure dimension is consistent between inputs
    queso_assert_equal_to( coord_indices.size(), this->dim() );

    // Make sure dimension is consisent with parameter space
    queso_assert_equal_to( coord_indices.size(), this->dim() );

    /* Mapping is: i + j*n_i + k*n_i*n_j + l*n_i*n_j*n_k + ...
       Initialize global_index to "i".
       Then loop and build up each term.*/
    unsigned int global_index = coord_indices[0];

    for( unsigned int d = 1; d < this->dim(); d++ )
      {
        // Accumulate the current term
        unsigned int idx = coord_indices[d];
        unsigned int local_d = d-1;
        do
          {
            idx *= n_points[local_d];
            local_d -= 1;
          } while( local_d >= 0 );

        global_index += idx;
      }

    return global_index;
  }

  template<class V, class M>
  void InterpolationSurrogateBase<V,M>::check_dim_consistency() const
  {
    if( this->dim() != this->m_n_points.size() )
      {
        std::stringstream vspace_dim;
        vspace_dim << this->m_domain.vectorSpace().dimGlobal();

        std::stringstream n_points_dim;
        n_points_dim << this->m_n_points.size();

        std::string error = "ERROR: Mismatch between dimension of parameter space and number of points\n.";
        error += "        domain dimension = " + vspace_dim.str() + "\n";
        error += "        points dimension = " + n_points_dim.str() + "\n";

        queso_error_msg(error);
      }
  }

  template<class V, class M>
  double InterpolationSurrogateBase<V,M>::spacing( unsigned int dim ) const
  {
    unsigned int n_intervals = this->m_n_points[dim]-1;
    double x_min = this->x_min(dim);
    double x_max = this->x_max(dim);

    return (x_max-x_min)/n_intervals;
  }

} // end namespace QUESO

// Instantiate
template class QUESO::InterpolationSurrogateBase<QUESO::GslVector,QUESO::GslMatrix>;
<|endoftext|>


<commit_before>#include "metadata_editor.h"
#include "halley/tools/project/project.h"
#include "halley/ui/ui_factory.h"
#include "halley/ui/ui_validator.h"
#include "halley/ui/widgets/ui_checkbox.h"
#include "halley/ui/widgets/ui_label.h"
#include "halley/ui/widgets/ui_textinput.h"
#include "src/ui/select_asset_widget.h"
using namespace Halley;

MetadataEditor::MetadataEditor(UIFactory& factory)
	: UIWidget("metadataEditor", {}, UISizer(UISizerType::Grid, 1, 2))
	, factory(factory)
{
}

void MetadataEditor::setResource(Project& p, AssetType type, const Path& path, Metadata effectiveMeta)
{
	assetType = type;
	filePath = path;
	project = &p;
	metadata = project->readMetadataFromDisk(filePath);
	effectiveMetadata = std::move(effectiveMeta);

	makeUI();
}

void MetadataEditor::onMetadataChanged()
{
	changed = true;
	getWidget("applyChanges")->setEnabled(true);
}

void MetadataEditor::saveMetadata()
{
	if (changed) {
		project->writeMetadataToDisk(filePath, metadata);
		changed = false;
		getWidget("applyChanges")->setEnabled(false);
	}
}

void MetadataEditor::makeUI()
{
	clear();
	add(factory.makeUI("ui/halley/metadata_editor"));
	fields = getWidget("fields");
	getWidget("applyChanges")->setEnabled(false);

	setHandle(UIEventType::ButtonClicked, "applyChanges", [=](const UIEvent& event)
	{
		saveMetadata();
	});

	const bool isAseprite = filePath.getExtension() == ".ase" || filePath.getExtension() == ".aseprite";

	switch (assetType) {
	case AssetType::Sprite:
	case AssetType::Animation:
		addInt2Field("Pivot", "pivotX", "pivotY", Vector2i());
		addInt4Field("Slices", "slice_left", "slice_top", "slice_right", "slice_bottom", Vector4i());
		if (isAseprite) {
			addBoolField("By Group", "group_separated", false);
		}
		addAssetTypeField("Material", "material", AssetType::MaterialDefinition, "Halley/Sprite");
		addStringField("Atlas", "atlas", "");
		addAssetTypeField("Palette", "palette", AssetType::Texture, "");
		addBoolField("Filtering", "filtering", false);
		addBoolField("Minimap", "minimap", false);
		addEnumField<TextureFormat>("Format", "format", "rgba");
		addEnumField<TextureAddressMode>("Address", "addressMode", "clamp");
		addInt2Field("Tile Split", "tileWidth", "tileHeight", Vector2i());
		addBoolField("Trim", "trim", true);
		addIntField("Padding", "padding", 0);
		break;

	case AssetType::AudioClip:
		addBoolField("Streaming", "streaming", false);
		addIntField("Loop Point", "loopPoint", 0);
		break;

	case AssetType::Font:
		addFloatField("Font Size", "fontSize", 0);
		addStringField("Font Name", "fontName", "");
		addInt2Field("Image Size", "width", "height", Vector2i(512, 512));
		addIntField("Supersample", "supersample", 4);
		addInt2Field("Range", "rangeStart", "rangeEnd", Vector2i(0, 255));
		addIntField("Ascender Adj.", "ascenderAdjustment", 0);
		addIntField("Line Spacing", "lineSpacing", 0);
		addFloatField("Radius", "radius", 8.0f);
		addStringField("Fallback", "fallback", "");
		addFloatField("Fallback Scale", "replacementScale", 1.0f);
		addStringField("Extra characters", "extraCharacters", "");
		break;
	}
}

void MetadataEditor::addIntField(const String& name, const String& key, int defaultValue)
{
	makeLabel(name);
	makeIntField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addInt2Field(const String& name, const String& x, const String& y, Vector2i defaultValue)
{
	makeLabel(name);
	auto sizer = std::make_shared<UISizer>();
	fields->add(sizer, 1);
	makeIntField(*sizer, x, defaultValue.x);
	makeIntField(*sizer, y, defaultValue.y);
}

void MetadataEditor::addInt4Field(const String& name, const String& x, const String& y, const String& z, const String& w, Vector4i defaultValue)
{
	makeLabel(name);
	auto sizer = std::make_shared<UISizer>();
	fields->add(sizer, 1);
	makeIntField(*sizer, x, defaultValue.x);
	makeIntField(*sizer, y, defaultValue.y);
	makeIntField(*sizer, z, defaultValue.z);
	makeIntField(*sizer, w, defaultValue.w);
}

void MetadataEditor::addFloatField(const String& name, const String& key, float defaultValue)
{
	makeLabel(name);
	makeFloatField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addBoolField(const String& name, const String& key, bool defaultValue)
{
	makeLabel(name);
	makeBoolField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addStringField(const String& name, const String& key, const String& defaultValue)
{
	makeLabel(name);
	makeStringField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addAssetTypeField(const String& name, const String& key, AssetType type, const String& defaultValue)
{
	makeLabel(name);
	makeAssetTypeField(fields->getSizer(), key, type, defaultValue);
}

void MetadataEditor::addDropdownField(const String& name, const String& key, std::vector<String> values, const String& defaultValue)
{
	makeLabel(name);
	makeDropdownField(fields->getSizer(), key, std::move(values), defaultValue);
}

void MetadataEditor::makeLabel(const String& name)
{
	fields->add(std::make_shared<UILabel>("", factory.getStyle("label").getTextRenderer("label"), LocalisedString::fromUserString(name)), 0, Vector4f(0, 0, 10, 0), UISizerAlignFlags::CentreVertical);
}

template <typename T>
static void updateMetadata(Metadata& metadata, const String& key, MetadataEditor& editor, const T& value, const T& defaultValue)
{
	if (value == defaultValue) {
		if (metadata.erase(key)) {
			editor.onMetadataChanged();
		}
	} else {
		if (metadata.set(key, value)) {
			editor.onMetadataChanged();
		}
	}
}

void MetadataEditor::setPivot(Vector2i pos)
{
	getWidgetAs<UITextInput>("pivotX")->setText(toString(pos.x));
	getWidgetAs<UITextInput>("pivotY")->setText(toString(pos.y));
}

String MetadataEditor::getMetaValue(const String& key) const
{
	return metadata.getString(key, effectiveMetadata.getString(key, ""));
}

void MetadataEditor::makeIntField(UISizer& sizer, const String& key, int defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	result->setValidator(std::make_shared<UINumericValidator>(true, false));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, toString(defaultValue));
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, toString(defaultValue));
	});
}

void MetadataEditor::makeFloatField(UISizer& sizer, const String& key, float defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	result->setValidator(std::make_shared<UINumericValidator>(true, true));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, toString(defaultValue));
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, toString(defaultValue));
	});
}

void MetadataEditor::makeBoolField(UISizer& sizer, const String& key, bool defaultValue)
{
	const auto result = std::make_shared<UICheckbox>(key, factory.getStyle("checkbox"));
	result->setMinSize(Vector2f(22, 22));
	sizer.add(result, 1, {}, UISizerAlignFlags::Left | UISizerAlignFlags::CentreVertical);

	const auto effectiveDefault = effectiveMetadata.getBool(":" + key, defaultValue);

	bindData(key, metadata.getBool(key, effectiveDefault), [=] (bool value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeStringField(UISizer& sizer, const String& key, const String& defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeDropdownField(UISizer& sizer, const String& key, std::vector<String> values, const String& defaultValue)
{
	const auto result = std::make_shared<UIDropdown>(key, factory.getStyle("dropdown"), factory.getStyle("scrollbar"), factory.getStyle("list"));
	result->setOptions(std::move(values));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, effectiveDefault);

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeAssetTypeField(UISizer& sizer, const String& key, AssetType type, const String& defaultValue)
{
	const auto result = std::make_shared<SelectAssetWidget>(key, factory, type);
	result->setGameResources(project->getGameResources());
	result->setMinSize(Vector2f(40, 22));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, effectiveDefault);

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}
<commit_msg>Added palette top line only option to metadata editor<commit_after>#include "metadata_editor.h"
#include "halley/tools/project/project.h"
#include "halley/ui/ui_factory.h"
#include "halley/ui/ui_validator.h"
#include "halley/ui/widgets/ui_checkbox.h"
#include "halley/ui/widgets/ui_label.h"
#include "halley/ui/widgets/ui_textinput.h"
#include "src/ui/select_asset_widget.h"
using namespace Halley;

MetadataEditor::MetadataEditor(UIFactory& factory)
	: UIWidget("metadataEditor", {}, UISizer(UISizerType::Grid, 1, 2))
	, factory(factory)
{
}

void MetadataEditor::setResource(Project& p, AssetType type, const Path& path, Metadata effectiveMeta)
{
	assetType = type;
	filePath = path;
	project = &p;
	metadata = project->readMetadataFromDisk(filePath);
	effectiveMetadata = std::move(effectiveMeta);

	makeUI();
}

void MetadataEditor::onMetadataChanged()
{
	changed = true;
	getWidget("applyChanges")->setEnabled(true);
}

void MetadataEditor::saveMetadata()
{
	if (changed) {
		project->writeMetadataToDisk(filePath, metadata);
		changed = false;
		getWidget("applyChanges")->setEnabled(false);
	}
}

void MetadataEditor::makeUI()
{
	clear();
	add(factory.makeUI("ui/halley/metadata_editor"));
	fields = getWidget("fields");
	getWidget("applyChanges")->setEnabled(false);

	setHandle(UIEventType::ButtonClicked, "applyChanges", [=](const UIEvent& event)
	{
		saveMetadata();
	});

	const bool isAseprite = filePath.getExtension() == ".ase" || filePath.getExtension() == ".aseprite";

	switch (assetType) {
	case AssetType::Sprite:
	case AssetType::Animation:
		addInt2Field("Pivot", "pivotX", "pivotY", Vector2i());
		addInt4Field("Slices", "slice_left", "slice_top", "slice_right", "slice_bottom", Vector4i());
		if (isAseprite) {
			addBoolField("By Group", "group_separated", false);
		}
		addAssetTypeField("Material", "material", AssetType::MaterialDefinition, "Halley/Sprite");
		addStringField("Atlas", "atlas", "");
		addAssetTypeField("Palette", "palette", AssetType::Texture, "");
		addBoolField("Palette Top Line Only", "paletteTopLineOnly", false);
		addBoolField("Filtering", "filtering", false);
		addBoolField("Minimap", "minimap", false);
		addEnumField<TextureFormat>("Format", "format", "rgba");
		addEnumField<TextureAddressMode>("Address", "addressMode", "clamp");
		addInt2Field("Tile Split", "tileWidth", "tileHeight", Vector2i());
		addBoolField("Trim", "trim", true);
		addIntField("Padding", "padding", 0);
		break;

	case AssetType::AudioClip:
		addBoolField("Streaming", "streaming", false);
		addIntField("Loop Point", "loopPoint", 0);
		break;

	case AssetType::Font:
		addFloatField("Font Size", "fontSize", 0);
		addStringField("Font Name", "fontName", "");
		addInt2Field("Image Size", "width", "height", Vector2i(512, 512));
		addIntField("Supersample", "supersample", 4);
		addInt2Field("Range", "rangeStart", "rangeEnd", Vector2i(0, 255));
		addIntField("Ascender Adj.", "ascenderAdjustment", 0);
		addIntField("Line Spacing", "lineSpacing", 0);
		addFloatField("Radius", "radius", 8.0f);
		addStringField("Fallback", "fallback", "");
		addFloatField("Fallback Scale", "replacementScale", 1.0f);
		addStringField("Extra characters", "extraCharacters", "");
		break;
	}
}

void MetadataEditor::addIntField(const String& name, const String& key, int defaultValue)
{
	makeLabel(name);
	makeIntField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addInt2Field(const String& name, const String& x, const String& y, Vector2i defaultValue)
{
	makeLabel(name);
	auto sizer = std::make_shared<UISizer>();
	fields->add(sizer, 1);
	makeIntField(*sizer, x, defaultValue.x);
	makeIntField(*sizer, y, defaultValue.y);
}

void MetadataEditor::addInt4Field(const String& name, const String& x, const String& y, const String& z, const String& w, Vector4i defaultValue)
{
	makeLabel(name);
	auto sizer = std::make_shared<UISizer>();
	fields->add(sizer, 1);
	makeIntField(*sizer, x, defaultValue.x);
	makeIntField(*sizer, y, defaultValue.y);
	makeIntField(*sizer, z, defaultValue.z);
	makeIntField(*sizer, w, defaultValue.w);
}

void MetadataEditor::addFloatField(const String& name, const String& key, float defaultValue)
{
	makeLabel(name);
	makeFloatField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addBoolField(const String& name, const String& key, bool defaultValue)
{
	makeLabel(name);
	makeBoolField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addStringField(const String& name, const String& key, const String& defaultValue)
{
	makeLabel(name);
	makeStringField(fields->getSizer(), key, defaultValue);
}

void MetadataEditor::addAssetTypeField(const String& name, const String& key, AssetType type, const String& defaultValue)
{
	makeLabel(name);
	makeAssetTypeField(fields->getSizer(), key, type, defaultValue);
}

void MetadataEditor::addDropdownField(const String& name, const String& key, std::vector<String> values, const String& defaultValue)
{
	makeLabel(name);
	makeDropdownField(fields->getSizer(), key, std::move(values), defaultValue);
}

void MetadataEditor::makeLabel(const String& name)
{
	fields->add(std::make_shared<UILabel>("", factory.getStyle("label").getTextRenderer("label"), LocalisedString::fromUserString(name)), 0, Vector4f(0, 0, 10, 0), UISizerAlignFlags::CentreVertical);
}

template <typename T>
static void updateMetadata(Metadata& metadata, const String& key, MetadataEditor& editor, const T& value, const T& defaultValue)
{
	if (value == defaultValue) {
		if (metadata.erase(key)) {
			editor.onMetadataChanged();
		}
	} else {
		if (metadata.set(key, value)) {
			editor.onMetadataChanged();
		}
	}
}

void MetadataEditor::setPivot(Vector2i pos)
{
	getWidgetAs<UITextInput>("pivotX")->setText(toString(pos.x));
	getWidgetAs<UITextInput>("pivotY")->setText(toString(pos.y));
}

String MetadataEditor::getMetaValue(const String& key) const
{
	return metadata.getString(key, effectiveMetadata.getString(key, ""));
}

void MetadataEditor::makeIntField(UISizer& sizer, const String& key, int defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	result->setValidator(std::make_shared<UINumericValidator>(true, false));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, toString(defaultValue));
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, toString(defaultValue));
	});
}

void MetadataEditor::makeFloatField(UISizer& sizer, const String& key, float defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	result->setValidator(std::make_shared<UINumericValidator>(true, true));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, toString(defaultValue));
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, toString(defaultValue));
	});
}

void MetadataEditor::makeBoolField(UISizer& sizer, const String& key, bool defaultValue)
{
	const auto result = std::make_shared<UICheckbox>(key, factory.getStyle("checkbox"));
	result->setMinSize(Vector2f(22, 22));
	sizer.add(result, 1, {}, UISizerAlignFlags::Left | UISizerAlignFlags::CentreVertical);

	const auto effectiveDefault = effectiveMetadata.getBool(":" + key, defaultValue);

	bindData(key, metadata.getBool(key, effectiveDefault), [=] (bool value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeStringField(UISizer& sizer, const String& key, const String& defaultValue)
{
	const auto result = std::make_shared<UITextInput>(key, factory.getStyle("inputThin"));
	result->setMinSize(Vector2f(40, 22));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, "");
	result->setGhostText(LocalisedString::fromUserString(effectiveDefault));

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeDropdownField(UISizer& sizer, const String& key, std::vector<String> values, const String& defaultValue)
{
	const auto result = std::make_shared<UIDropdown>(key, factory.getStyle("dropdown"), factory.getStyle("scrollbar"), factory.getStyle("list"));
	result->setOptions(std::move(values));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, effectiveDefault);

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}

void MetadataEditor::makeAssetTypeField(UISizer& sizer, const String& key, AssetType type, const String& defaultValue)
{
	const auto result = std::make_shared<SelectAssetWidget>(key, factory, type);
	result->setGameResources(project->getGameResources());
	result->setMinSize(Vector2f(40, 22));
	sizer.add(result, 1);

	const auto effectiveDefault = effectiveMetadata.getString(":" + key, defaultValue);
	const auto value = metadata.getString(key, effectiveDefault);

	bindData(key, value, [=] (const String& value)
	{
		updateMetadata(metadata, key, *this, value, defaultValue);
	});
}
<|endoftext|>


<commit_before>#include "acmacs-base/debug.hh"

#include "time-series-draw.hh"
#include "tree.hh"
#include "tree-draw.hh"
#include "coloring.hh"

// ----------------------------------------------------------------------

void TimeSeriesDraw::prepare()
{
    std::map<date::year_month_day, size_t> sequences_per_month;
    mTree.sequences_per_month(sequences_per_month);
    if (!sequences_per_month.empty()) {
        std::cout << "INFO: Sequences per month:" << '\n';
        for (const auto& e: sequences_per_month) {
            std::cout << "  " << e.first << " " << e.second << '\n';
        }

        const auto today = date::today();
        auto end_of_ts = today;
        if (mSettings.end.empty()) {
            for (auto ms = sequences_per_month.crbegin(); ms != sequences_per_month.crend(); ++ms) {
                if (ms->second && ms->first <= today) {
                    end_of_ts = ms->first;
                    mSettings.end = date::display(date::end_of_month(ms->first));
                    break;
                }
            }
        }

        if (mSettings.begin.empty()) {
            for (const auto& entry : sequences_per_month) {
                if (entry.second && months_between_dates(entry.first, end_of_ts) < 25) {
                    mSettings.begin = date::display(entry.first);
                    break;
                }
            }
        }

        mNumberOfMonths = static_cast<size_t>(calendar_months_between_dates_inclusive(date::from_string(*mSettings.begin), date::from_string(*mSettings.end)));
        std::cout << "INFO: dates to show: " << mSettings.begin << " .. " << mSettings.end << "  months: " << mNumberOfMonths << DEBUG_LINE_FUNC << '\n';
    }
    else {
        std::cout << "WARNING: no dates found for sequences" << DEBUG_LINE_FUNC << '\n';
        mNumberOfMonths = 0;
    }

} // TimeSeriesDraw::prepare

// ----------------------------------------------------------------------

std::vector<std::string> TimeSeriesDraw::all_months() const
{
    std::vector<std::string> result;
    auto current_month{date::from_string(*mSettings.begin)};
    for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month))
        result.push_back(date::year4_month2(current_month));
    return result;

} // TimeSeriesDraw::all_months

// ----------------------------------------------------------------------

void TimeSeriesDraw::init_settings(const SettingsInitializer& /*settings_initilizer*/)
{

} // TimeSeriesDraw::init_settings

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw()
{
    if (mNumberOfMonths) {
          // mSurface.border("green3", 1);
        const double month_width = mSurface.viewport().size.width / mNumberOfMonths;
        draw_labels(month_width);
        draw_month_separators(month_width);
        draw_dashes(month_width);
        draw_hz_section_lines();
    }

} // TimeSeriesDraw::draw

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_labels(double month_width)
{
    const acmacs::Size& surface_size = mSurface.viewport().size;
    const double month_max_height = mSurface.text_size("May ", Pixels{mSettings.label_size}, mSettings.label_style).width;
    double x_bearing;
    const auto big_label_size = mSurface.text_size("May 99", Pixels{mSettings.label_size}, mSettings.label_style, &x_bearing);
    const auto text_up = (month_width - big_label_size.height) * 0.5;
    const double month_year_to_timeseries_gap = mSurface.convert(Pixels{mSettings.month_year_to_timeseries_gap}).value();

    draw_labels_at_side({text_up, - big_label_size.width - x_bearing - 2 /*month_year_to_timeseries_gap*/}, month_width, month_max_height);
    draw_labels_at_side({text_up, surface_size.height + x_bearing + month_year_to_timeseries_gap}, month_width, month_max_height);

} // TimeSeriesDraw::draw_labels

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_labels_at_side(const acmacs::PointCoordinates& aOrigin, double month_width, double month_max_height)
{
    try {
        auto current_month{date::from_string(*mSettings.begin)};
        for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month)) {
            const double left = aOrigin.x() + month_no * month_width;
            mSurface.text({left, aOrigin.y()}, date::month_3(current_month), 0, Pixels{mSettings.label_size}, mSettings.label_style, Rotation{M_PI_2});
            mSurface.text({left, aOrigin.y() + month_max_height}, date::year_2(current_month), 0, Pixels{mSettings.label_size}, mSettings.label_style, Rotation{M_PI_2});
        }
    }
    catch (std::exception& err) {
        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_labels_at_side)\n";
    }

} // TimeSeriesDraw::draw_labels_at_side

// ----------------------------------------------------------------------

// for tracked antigens in antigenic maps colored by date
void TimeSeriesDraw::draw_color_scale(const std::map<std::string, Color, std::less<>>& aTrackedAntigenColorByMonth)
{
    const acmacs::Size& surface_size = mSurface.viewport().size;
    const double month_width = mSurface.viewport().size.width / mNumberOfMonths;
    const auto top = surface_size.height;
    auto current_month{date::from_string(*mSettings.begin)};
    for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month)) {
        const auto left = month_no * month_width;
        mSurface.rectangle_filled({left, top}, acmacs::Size{10, 10}, PINK, Pixels{0}, aTrackedAntigenColorByMonth.find(date::year4_month2(current_month))->second);
    }

} // TimeSeriesDraw::draw_color_scale

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_month_separators(double month_width)
{
    const auto first_month_no = static_cast<unsigned>(date::from_string(*mSettings.begin).month());
    const auto thick_separator_base  = (13 - first_month_no) % 12;

    const double bottom = mSurface.viewport().size.height;
    for (size_t month_no = 0; month_no <= mNumberOfMonths; ++month_no) {
        const double left = month_no * month_width;
        const double thickness = (month_no % 12) == thick_separator_base ? 2.0 : 1.0;
        mSurface.line({left, 0}, {left, bottom}, mSettings.month_separator_color, Pixels{mSettings.month_separator_width * thickness});
    }

} // TimeSeriesDraw::draw_month_separators

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_dashes(double month_width)
{
    const double base_x = month_width * (1.0 - mSettings.dash_width) / 2;
    const Coloring& coloring = mTreeDraw.coloring();

    const auto begin{date::from_string(*mSettings.begin)}, end{date::from_string(*mSettings.end)};
    auto draw_dash = [&](const Node& aNode) {
        if (aNode.draw.shown && !aNode.data.date().empty()) {
            if (const auto node_date_s = aNode.data.date(); node_date_s.size() > 3 && node_date_s.substr(node_date_s.size() - 3) != "-00") { // ignore incomplete dates
                try {
                    if (const auto node_date{date::from_string(node_date_s)}; node_date >= begin && node_date <= end) {
                        const int month_no = date::months_between_dates(begin, node_date);
                        const acmacs::PointCoordinates a(base_x + month_width * month_no, aNode.draw.vertical_pos);
                        mSurface.line(a, {a.x() + month_width * mSettings.dash_width, a.y()}, coloring.color(aNode), Pixels{mSettings.dash_line_width}, acmacs::surface::LineCap::Round);
                    }
                }
                catch (std::exception& err) {
                    if (aNode.data.date().size() > 4)
                        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_dashes) Date: " << aNode.data.date() << "\n";
                }
            }
        }
    };

    try {
        tree::iterate_leaf(mTree, draw_dash);
    }
    catch (std::exception& err) {
        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_dashes)\n";
    }

} // TimeSeriesDraw::draw_dashes

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_hz_section_lines()
{
    double previous_vertical_pos = -1e-8;
    auto draw = [&](const Node& aNode) {
        if (aNode.draw.shown) {
            if (aNode.draw.hz_section_index != NodeDrawData::HzSectionNoIndex) {
                const auto section_settings = mHzSections.sections[aNode.draw.hz_section_index];
                double y = aNode.draw.vertical_pos;
                if (section_settings->show_line) {
                    y = (previous_vertical_pos + aNode.draw.vertical_pos) / 2;
                    mSurface.line({0, y}, {mSurface.viewport().size.width, y}, mHzSections.line_color, Pixels{mHzSections.line_width});
                }
                if ((!mTreeMode || mHzSections.show_labels_in_time_series_in_tree_mode) && section_settings->show_label_in_time_series) {
                    draw_hz_section_label(aNode.draw.hz_section_index, y);
                }
            }
            previous_vertical_pos = aNode.draw.vertical_pos;
        }
    };
    tree::iterate_leaf(mTree, draw);

} // TimeSeriesDraw::draw_hz_section_lines

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_hz_section_label(size_t aSectionIndex, double aY)
{
    const auto section_settings = mHzSections.sections[aSectionIndex];
    if (section_settings->show && section_settings->show_map) {
        std::string label = mHzSections.node_refs[aSectionIndex].index; // (1, 'A' + static_cast<char>(aSectionNo));
        const acmacs::Size tsize = mSurface.text_size(label, Pixels{mHzSections.ts_label_size}, mHzSections.ts_label_style);
        mSurface.text({mSurface.viewport().size.width - tsize.width * 1.2, aY + tsize.height * 1.2}, label, mHzSections.ts_label_color, Pixels{mHzSections.ts_label_size}, mHzSections.ts_label_style);
    }

} // TimeSeriesDraw::draw_hz_section_label

// ----------------------------------------------------------------------

// void TimeSeriesDraw::hide_hz_section_labels_in_time_series()
// {
//     for (auto& section: mHzSections.sections)
//         section.show_label_in_time_series = false;

// } // TimeSeriesDraw::hide_hz_section_labels_in_time_series

// ----------------------------------------------------------------------

void TimeSeriesDrawSettings::remove_for_tree_settings()
{
    label_style.remove();

} // TimeSeriesDrawSettings::remove_for_tree_settings

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>no year separators in time series<commit_after>#include "acmacs-base/debug.hh"

#include "time-series-draw.hh"
#include "tree.hh"
#include "tree-draw.hh"
#include "coloring.hh"

// ----------------------------------------------------------------------

void TimeSeriesDraw::prepare()
{
    std::map<date::year_month_day, size_t> sequences_per_month;
    mTree.sequences_per_month(sequences_per_month);
    if (!sequences_per_month.empty()) {
        std::cout << "INFO: Sequences per month:" << '\n';
        for (const auto& e: sequences_per_month) {
            std::cout << "  " << e.first << " " << e.second << '\n';
        }

        const auto today = date::today();
        auto end_of_ts = today;
        if (mSettings.end.empty()) {
            for (auto ms = sequences_per_month.crbegin(); ms != sequences_per_month.crend(); ++ms) {
                if (ms->second && ms->first <= today) {
                    end_of_ts = ms->first;
                    mSettings.end = date::display(date::end_of_month(ms->first));
                    break;
                }
            }
        }

        if (mSettings.begin.empty()) {
            for (const auto& entry : sequences_per_month) {
                if (entry.second && months_between_dates(entry.first, end_of_ts) < 25) {
                    mSettings.begin = date::display(entry.first);
                    break;
                }
            }
        }

        mNumberOfMonths = static_cast<size_t>(calendar_months_between_dates_inclusive(date::from_string(*mSettings.begin), date::from_string(*mSettings.end)));
        std::cout << "INFO: dates to show: " << mSettings.begin << " .. " << mSettings.end << "  months: " << mNumberOfMonths << DEBUG_LINE_FUNC << '\n';
    }
    else {
        std::cout << "WARNING: no dates found for sequences" << DEBUG_LINE_FUNC << '\n';
        mNumberOfMonths = 0;
    }

} // TimeSeriesDraw::prepare

// ----------------------------------------------------------------------

std::vector<std::string> TimeSeriesDraw::all_months() const
{
    std::vector<std::string> result;
    auto current_month{date::from_string(*mSettings.begin)};
    for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month))
        result.push_back(date::year4_month2(current_month));
    return result;

} // TimeSeriesDraw::all_months

// ----------------------------------------------------------------------

void TimeSeriesDraw::init_settings(const SettingsInitializer& /*settings_initilizer*/)
{

} // TimeSeriesDraw::init_settings

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw()
{
    if (mNumberOfMonths) {
          // mSurface.border("green3", 1);
        const double month_width = mSurface.viewport().size.width / mNumberOfMonths;
        draw_labels(month_width);
        draw_month_separators(month_width);
        draw_dashes(month_width);
        draw_hz_section_lines();
    }

} // TimeSeriesDraw::draw

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_labels(double month_width)
{
    const acmacs::Size& surface_size = mSurface.viewport().size;
    const double month_max_height = mSurface.text_size("May ", Pixels{mSettings.label_size}, mSettings.label_style).width;
    double x_bearing;
    const auto big_label_size = mSurface.text_size("May 99", Pixels{mSettings.label_size}, mSettings.label_style, &x_bearing);
    const auto text_up = (month_width - big_label_size.height) * 0.5;
    const double month_year_to_timeseries_gap = mSurface.convert(Pixels{mSettings.month_year_to_timeseries_gap}).value();

    draw_labels_at_side({text_up, - big_label_size.width - x_bearing - 2 /*month_year_to_timeseries_gap*/}, month_width, month_max_height);
    draw_labels_at_side({text_up, surface_size.height + x_bearing + month_year_to_timeseries_gap}, month_width, month_max_height);

} // TimeSeriesDraw::draw_labels

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_labels_at_side(const acmacs::PointCoordinates& aOrigin, double month_width, double month_max_height)
{
    try {
        auto current_month{date::from_string(*mSettings.begin)};
        for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month)) {
            const double left = aOrigin.x() + month_no * month_width;
            mSurface.text({left, aOrigin.y()}, date::month_3(current_month), 0, Pixels{mSettings.label_size}, mSettings.label_style, Rotation{M_PI_2});
            mSurface.text({left, aOrigin.y() + month_max_height}, date::year_2(current_month), 0, Pixels{mSettings.label_size}, mSettings.label_style, Rotation{M_PI_2});
        }
    }
    catch (std::exception& err) {
        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_labels_at_side)\n";
    }

} // TimeSeriesDraw::draw_labels_at_side

// ----------------------------------------------------------------------

// for tracked antigens in antigenic maps colored by date
void TimeSeriesDraw::draw_color_scale(const std::map<std::string, Color, std::less<>>& aTrackedAntigenColorByMonth)
{
    const acmacs::Size& surface_size = mSurface.viewport().size;
    const double month_width = mSurface.viewport().size.width / mNumberOfMonths;
    const auto top = surface_size.height;
    auto current_month{date::from_string(*mSettings.begin)};
    for (size_t month_no = 0; month_no < mNumberOfMonths; ++month_no, date::increment_month(current_month)) {
        const auto left = month_no * month_width;
        mSurface.rectangle_filled({left, top}, acmacs::Size{10, 10}, PINK, Pixels{0}, aTrackedAntigenColorByMonth.find(date::year4_month2(current_month))->second);
    }

} // TimeSeriesDraw::draw_color_scale

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_month_separators(double month_width)
{
    const auto first_month_no = static_cast<unsigned>(date::from_string(*mSettings.begin).month());
    const auto thick_separator_base  = (13 - first_month_no) % 12;

    const double bottom = mSurface.viewport().size.height;
    for (size_t month_no = 0; month_no <= mNumberOfMonths; ++month_no) {
        const double left = month_no * month_width;
        const double thickness = 1.0; // (month_no % 12) == thick_separator_base ? 2.0 : 1.0;
        mSurface.line({left, 0}, {left, bottom}, mSettings.month_separator_color, Pixels{mSettings.month_separator_width * thickness});
    }

} // TimeSeriesDraw::draw_month_separators

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_dashes(double month_width)
{
    const double base_x = month_width * (1.0 - mSettings.dash_width) / 2;
    const Coloring& coloring = mTreeDraw.coloring();

    const auto begin{date::from_string(*mSettings.begin)}, end{date::from_string(*mSettings.end)};
    auto draw_dash = [&](const Node& aNode) {
        if (aNode.draw.shown && !aNode.data.date().empty()) {
            if (const auto node_date_s = aNode.data.date(); node_date_s.size() > 3 && node_date_s.substr(node_date_s.size() - 3) != "-00") { // ignore incomplete dates
                try {
                    if (const auto node_date{date::from_string(node_date_s)}; node_date >= begin && node_date <= end) {
                        const int month_no = date::months_between_dates(begin, node_date);
                        const acmacs::PointCoordinates a(base_x + month_width * month_no, aNode.draw.vertical_pos);
                        mSurface.line(a, {a.x() + month_width * mSettings.dash_width, a.y()}, coloring.color(aNode), Pixels{mSettings.dash_line_width}, acmacs::surface::LineCap::Round);
                    }
                }
                catch (std::exception& err) {
                    if (aNode.data.date().size() > 4)
                        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_dashes) Date: " << aNode.data.date() << "\n";
                }
            }
        }
    };

    try {
        tree::iterate_leaf(mTree, draw_dash);
    }
    catch (std::exception& err) {
        std::cerr << "WARNING: " << err.what() << " (TimeSeriesDraw::draw_dashes)\n";
    }

} // TimeSeriesDraw::draw_dashes

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_hz_section_lines()
{
    double previous_vertical_pos = -1e-8;
    auto draw = [&](const Node& aNode) {
        if (aNode.draw.shown) {
            if (aNode.draw.hz_section_index != NodeDrawData::HzSectionNoIndex) {
                const auto section_settings = mHzSections.sections[aNode.draw.hz_section_index];
                double y = aNode.draw.vertical_pos;
                if (section_settings->show_line) {
                    y = (previous_vertical_pos + aNode.draw.vertical_pos) / 2;
                    mSurface.line({0, y}, {mSurface.viewport().size.width, y}, mHzSections.line_color, Pixels{mHzSections.line_width});
                }
                if ((!mTreeMode || mHzSections.show_labels_in_time_series_in_tree_mode) && section_settings->show_label_in_time_series) {
                    draw_hz_section_label(aNode.draw.hz_section_index, y);
                }
            }
            previous_vertical_pos = aNode.draw.vertical_pos;
        }
    };
    tree::iterate_leaf(mTree, draw);

} // TimeSeriesDraw::draw_hz_section_lines

// ----------------------------------------------------------------------

void TimeSeriesDraw::draw_hz_section_label(size_t aSectionIndex, double aY)
{
    const auto section_settings = mHzSections.sections[aSectionIndex];
    if (section_settings->show && section_settings->show_map) {
        std::string label = mHzSections.node_refs[aSectionIndex].index; // (1, 'A' + static_cast<char>(aSectionNo));
        const acmacs::Size tsize = mSurface.text_size(label, Pixels{mHzSections.ts_label_size}, mHzSections.ts_label_style);
        mSurface.text({mSurface.viewport().size.width - tsize.width * 1.2, aY + tsize.height * 1.2}, label, mHzSections.ts_label_color, Pixels{mHzSections.ts_label_size}, mHzSections.ts_label_style);
    }

} // TimeSeriesDraw::draw_hz_section_label

// ----------------------------------------------------------------------

// void TimeSeriesDraw::hide_hz_section_labels_in_time_series()
// {
//     for (auto& section: mHzSections.sections)
//         section.show_label_in_time_series = false;

// } // TimeSeriesDraw::hide_hz_section_labels_in_time_series

// ----------------------------------------------------------------------

void TimeSeriesDrawSettings::remove_for_tree_settings()
{
    label_style.remove();

} // TimeSeriesDrawSettings::remove_for_tree_settings

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>