<commit_before>#include <tiramisu/expr.h>
#include <tiramisu/core.h>
#include "mkl.h"
#include <stdio.h>
#include <stdlib.h>
#define min(x,y) (((x) < (y)) ? (x) : (y))
namespace tiramisu
{

tiramisu::expr& tiramisu::expr::operator=(tiramisu::expr const & e)
{
    this->_operator = e._operator;
    this->op = e.op;
    this->access_vector = e.access_vector;
    this->argument_vector = e.argument_vector;
    this->defined = e.defined;
    this->name = e.name;
    this->dtype = e.dtype;
    this->etype = e.etype;

    // Copy the integer value
    if (e.get_expr_type() == tiramisu::e_val)
    {
        if (e.get_data_type() == tiramisu::p_uint8)
        {
            this->uint8_value = e.get_uint8_value();
        }
        else if (e.get_data_type() == tiramisu::p_int8)
        {
            this->int8_value = e.get_int8_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint16)
        {
            this->uint16_value = e.get_uint16_value();
        }
        else if (e.get_data_type() == tiramisu::p_int16)
        {
            this->int16_value = e.get_int16_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint32)
        {
            this->uint32_value = e.get_uint32_value();
        }
        else if (e.get_data_type() == tiramisu::p_int32)
        {
            this->int32_value = e.get_int32_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint64)
        {
            this->uint64_value = e.get_uint64_value();
        }
        else if (e.get_data_type() == tiramisu::p_int64)
        {
            this->int64_value = e.get_int64_value();
        }
        else if (e.get_data_type() == tiramisu::p_float32)
        {
            this->float32_value = e.get_float32_value();
        }
        else if (e.get_data_type() == tiramisu::p_float64)
        {
            this->float64_value = e.get_float64_value();
        }
    }
    return *this;
}

tiramisu::expr tiramisu::expr::substitute(std::vector<std::pair<var, expr>> substitutions) const
{
    for (auto &substitution: substitutions)
        if (this->is_equal(substitution.first))
            return substitution.second;

    return apply_to_operands([&substitutions](const expr& e){
        return e.substitute(substitutions);
    });
}

tiramisu::expr tiramisu::expr::substitute_access(std::string original, std::string substitute) const {
    expr && result = this->apply_to_operands([&original, &substitute](const expr& e){
        return e.substitute_access(original, substitute);
    });
    if (result.get_op_type() == o_access && result.name == original)
    {
        result.name = substitute;
    }
    return result;
}

tiramisu::var::var(std::string name, bool save)
{
    assert(!name.empty());

    auto declared = var::declared_vars.find(name);

    if (declared != var::declared_vars.end())
    {
        *this = declared->second;
    }
    else
    {
        this->name = name;
        this->etype = tiramisu::e_var;
        this->dtype = global::get_loop_iterator_data_type();
        this->defined = true;
        if (save)
        {
            var::declared_vars.insert(std::make_pair(name, *this));
            DEBUG(3, std::cout << "Saved variable " << this->name << " of type " << str_from_tiramisu_type_primitive(this->dtype));
        }
    }
}

tiramisu::var::var(tiramisu::primitive_t type, std::string name, bool save)
{
    assert(!name.empty());

    auto declared = var::declared_vars.find(name);

    if (declared != var::declared_vars.end())
    {
        assert(declared->second.dtype == type);
        *this = declared->second;
    }
    else
    {
        this->name = name;
        this->etype = tiramisu::e_var;
        this->dtype = type;
        this->defined = true;
        if (save)
        {
            var::declared_vars.insert(std::make_pair(name, *this));
            DEBUG(10, std::cout << "Saved variable " << this->name << " of type " << str_from_tiramisu_type_primitive(this->dtype));
        }
    }
}

tiramisu::expr tiramisu::expr::copy() const
{
    return (*this);
}

std::unordered_map<std::string, var> tiramisu::var::declared_vars;

expr cast(primitive_t tT, const expr & e) {
    if (e.get_data_type() == tT)
        return e;
    return expr{o_cast, tT, e};
}

expr tiramisu::expr::operator+(tiramisu::expr other) const {
    return tiramisu::expr{o_add, *this, other};
}

expr tiramisu::expr::operator-(tiramisu::expr other) const {
    return tiramisu::expr{o_sub, *this, other};
}

expr tiramisu::expr::operator*(tiramisu::expr other) const {
    return tiramisu::expr{o_mul, *this, other};
}

expr tiramisu::expr::operator/(tiramisu::expr other) const {
    return tiramisu::expr{o_div, *this, other};
}

expr tiramisu::expr::operator%(tiramisu::expr other) const {
    return tiramisu::expr{o_mod, *this, other};
}

expr tiramisu::expr::operator>>(tiramisu::expr other) const {
    return tiramisu::expr{o_right_shift, *this, other};
}

expr tiramisu::expr::operator<<(tiramisu::expr other) const {
    return tiramisu::expr{o_left_shift, *this, other};
}

expr memcpy(const buffer &from, const buffer &to) {
    return expr(o_memcpy, var(p_void_ptr, from.get_name()), var(p_void_ptr, to.get_name()));
}

expr allocate(const buffer &b)
{
    return expr{o_allocate, b.get_name()};
}

expr cublas_gemm(const buffer &A, const buffer &B, buffer &C,
                 expr M, expr N, expr K,
                 expr alpha, expr beta,
                 expr ldA, expr ldB, expr ldC,
                 expr offsetA, expr offsetB, expr offsetC,
                 expr transposeA, expr transposeB)
{
    if (A.get_location() != cuda_ast::memory_location::global ||
        B.get_location() != cuda_ast::memory_location::global ||
        C.get_location() != cuda_ast::memory_location::global) {
        ERROR("Buffers must be on GPU global memory", true);
    }
    std::string fname;
    expr alpha_expr;
    expr beta_expr;
    if (A.get_elements_type() == p_float32 &&
        B.get_elements_type() == p_float32 &&
        C.get_elements_type() == p_float32) {
        fname = "tiramisu_cublas_sgemm";
        alpha_expr = cast(p_float32, alpha);
        beta_expr = cast(p_float32, beta);
    } else if (A.get_elements_type() == p_float64 &&
               B.get_elements_type() == p_float64 &&
               C.get_elements_type() == p_float64) {
        fname = "tiramisu_cublas_dgemm";
        alpha_expr = cast(p_float64, alpha);
        beta_expr = cast(p_float64, beta);
    } else {
        ERROR("All input buffers should be of same type and either p_float32 or p_float64", true);
    }
    return expr(o_call, fname,
            {
                var(p_void_ptr, A.get_name()),
                var(p_void_ptr, B.get_name()),
                var(p_void_ptr, C.get_name()),
                cast(p_uint64, M), cast(p_uint64, N), cast(p_uint64, K),
                alpha_expr, beta_expr,
                cast(p_uint64, ldA), cast(p_uint64, ldB), cast(p_uint64, ldC),
                cast(p_uint64, offsetA), cast(p_uint64, offsetB), cast(p_uint64, offsetC),
                cast(p_boolean, transposeA), cast(p_boolean, transposeB)
            },
            tiramisu::p_uint8);
}

expr cuda_stream_synchronize()
{
    return expr(o_call, "tiramisu_cuda_stream_synchronize", {int32_t(0)}, tiramisu::p_int32);
}

extern "C"
int tiramisu_cblas_sgemm(float *A, float *B, float *C,
                          uint64_t M, uint64_t N, uint64_t K,
                          float alpha, float beta,
                          uint64_t ldA, uint64_t ldB, uint64_t ldC,
                          uint64_t offsetA, uint64_t offsetB, uint64_t offsetC,
                          bool transposeA, bool transposeB)
{
    // Default values for tight packing:
    if (ldA == 0) {
        ldA = transposeA ? M : K;
    }
    if (ldB == 0) {
        ldB = transposeB ? K : N;
    }
    if (ldC == 0) {
        ldC = N;
    }

    cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                M, N, K, alpha, A+offsetA, K, B+ offsetB, N, beta, C+ offsetC, N);
    return 0;
}

extern "C"
int tiramisu_cblas_dgemm(double *A, double *B, double *C,
                          uint64_t M, uint64_t N, uint64_t K,
                          double alpha, double beta,
                          uint64_t ldA, uint64_t ldB, uint64_t ldC,
                          uint64_t offsetA, uint64_t offsetB, uint64_t offsetC,
                          bool transposeA, bool transposeB)
{
    // Default values for tight packing:
    if (ldA == 0) {
        ldA = transposeA ? M : K;
    }
    if (ldB == 0) {
        ldB = transposeB ? K : N;
    }
    if (ldC == 0) {
        ldC = N;
    }

    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                M, N, K, alpha, A+offsetA, K, B+ offsetB, N, beta, C+ offsetC, N);
    return 0;
}

expr cblas_gemm_call(const buffer &A, const buffer &B, buffer &C,
                 expr M, expr N, expr K,
                 expr alpha, expr beta,
                 expr ldA, expr ldB, expr ldC,
                 expr offsetA, expr offsetB, expr offsetC,
                 expr transposeA, expr transposeB)
{
    std::string fname;
    expr alpha_expr;
    expr beta_expr;
    if (A.get_elements_type() == p_float32 &&
        B.get_elements_type() == p_float32 &&
        C.get_elements_type() == p_float32) {
        fname = "tiramisu_cblas_sgemm";
        alpha_expr = cast(p_float32, alpha);
        beta_expr = cast(p_float32, beta);
    } else if (A.get_elements_type() == p_float64 &&
               B.get_elements_type() == p_float64 &&
               C.get_elements_type() == p_float64) {
        fname = "tiramisu_cblas_dgemm";
        alpha_expr = cast(p_float64, alpha);
        beta_expr = cast(p_float64, beta);
    } else {
        ERROR("All input buffers should be of same type and either p_float32 or p_float64", true);
    }
    return expr(o_call, fname,
            {
                var(p_void_ptr, A.get_name()),
                var(p_void_ptr, B.get_name()),
                var(p_void_ptr, C.get_name()),
                cast(p_uint64, M), cast(p_uint64, N), cast(p_uint64, K),
                alpha_expr, beta_expr,
                cast(p_uint64, ldA), cast(p_uint64, ldB), cast(p_uint64, ldC),
                cast(p_uint64, offsetA), cast(p_uint64, offsetB), cast(p_uint64, offsetC),
                cast(p_boolean, transposeA), cast(p_boolean, transposeB)
            },
            tiramisu::p_uint8);
}

}
<commit_msg>Update tiramisu_expr.cpp<commit_after>#include <tiramisu/expr.h>
#include <tiramisu/core.h>
#include "/opt/intel/compilers_and_libraries_2017.5.239/linux/mkl/include/mkl.h"

namespace tiramisu
{

tiramisu::expr& tiramisu::expr::operator=(tiramisu::expr const & e)
{
    this->_operator = e._operator;
    this->op = e.op;
    this->access_vector = e.access_vector;
    this->argument_vector = e.argument_vector;
    this->defined = e.defined;
    this->name = e.name;
    this->dtype = e.dtype;
    this->etype = e.etype;

    // Copy the integer value
    if (e.get_expr_type() == tiramisu::e_val)
    {
        if (e.get_data_type() == tiramisu::p_uint8)
        {
            this->uint8_value = e.get_uint8_value();
        }
        else if (e.get_data_type() == tiramisu::p_int8)
        {
            this->int8_value = e.get_int8_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint16)
        {
            this->uint16_value = e.get_uint16_value();
        }
        else if (e.get_data_type() == tiramisu::p_int16)
        {
            this->int16_value = e.get_int16_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint32)
        {
            this->uint32_value = e.get_uint32_value();
        }
        else if (e.get_data_type() == tiramisu::p_int32)
        {
            this->int32_value = e.get_int32_value();
        }
        else if (e.get_data_type() == tiramisu::p_uint64)
        {
            this->uint64_value = e.get_uint64_value();
        }
        else if (e.get_data_type() == tiramisu::p_int64)
        {
            this->int64_value = e.get_int64_value();
        }
        else if (e.get_data_type() == tiramisu::p_float32)
        {
            this->float32_value = e.get_float32_value();
        }
        else if (e.get_data_type() == tiramisu::p_float64)
        {
            this->float64_value = e.get_float64_value();
        }
    }
    return *this;
}

tiramisu::expr tiramisu::expr::substitute(std::vector<std::pair<var, expr>> substitutions) const
{
    for (auto &substitution: substitutions)
        if (this->is_equal(substitution.first))
            return substitution.second;

    return apply_to_operands([&substitutions](const expr& e){
        return e.substitute(substitutions);
    });
}

tiramisu::expr tiramisu::expr::substitute_access(std::string original, std::string substitute) const {
    expr && result = this->apply_to_operands([&original, &substitute](const expr& e){
        return e.substitute_access(original, substitute);
    });
    if (result.get_op_type() == o_access && result.name == original)
    {
        result.name = substitute;
    }
    return result;
}

tiramisu::var::var(std::string name, bool save)
{
    assert(!name.empty());

    auto declared = var::declared_vars.find(name);

    if (declared != var::declared_vars.end())
    {
        *this = declared->second;
    }
    else
    {
        this->name = name;
        this->etype = tiramisu::e_var;
        this->dtype = global::get_loop_iterator_data_type();
        this->defined = true;
        if (save)
        {
            var::declared_vars.insert(std::make_pair(name, *this));
            DEBUG(3, std::cout << "Saved variable " << this->name << " of type " << str_from_tiramisu_type_primitive(this->dtype));
        }
    }
}

tiramisu::var::var(tiramisu::primitive_t type, std::string name, bool save)
{
    assert(!name.empty());

    auto declared = var::declared_vars.find(name);

    if (declared != var::declared_vars.end())
    {
        assert(declared->second.dtype == type);
        *this = declared->second;
    }
    else
    {
        this->name = name;
        this->etype = tiramisu::e_var;
        this->dtype = type;
        this->defined = true;
        if (save)
        {
            var::declared_vars.insert(std::make_pair(name, *this));
            DEBUG(10, std::cout << "Saved variable " << this->name << " of type " << str_from_tiramisu_type_primitive(this->dtype));
        }
    }
}

tiramisu::expr tiramisu::expr::copy() const
{
    return (*this);
}

std::unordered_map<std::string, var> tiramisu::var::declared_vars;

expr cast(primitive_t tT, const expr & e) {
    if (e.get_data_type() == tT)
        return e;
    return expr{o_cast, tT, e};
}

expr tiramisu::expr::operator+(tiramisu::expr other) const {
    return tiramisu::expr{o_add, *this, other};
}

expr tiramisu::expr::operator-(tiramisu::expr other) const {
    return tiramisu::expr{o_sub, *this, other};
}

expr tiramisu::expr::operator*(tiramisu::expr other) const {
    return tiramisu::expr{o_mul, *this, other};
}

expr tiramisu::expr::operator/(tiramisu::expr other) const {
    return tiramisu::expr{o_div, *this, other};
}

expr tiramisu::expr::operator%(tiramisu::expr other) const {
    return tiramisu::expr{o_mod, *this, other};
}

expr tiramisu::expr::operator>>(tiramisu::expr other) const {
    return tiramisu::expr{o_right_shift, *this, other};
}

expr tiramisu::expr::operator<<(tiramisu::expr other) const {
    return tiramisu::expr{o_left_shift, *this, other};
}

expr memcpy(const buffer &from, const buffer &to) {
    return expr(o_memcpy, var(p_void_ptr, from.get_name()), var(p_void_ptr, to.get_name()));
}

expr allocate(const buffer &b)
{
    return expr{o_allocate, b.get_name()};
}

expr cublas_gemm(const buffer &A, const buffer &B, buffer &C,
                 expr M, expr N, expr K,
                 expr alpha, expr beta,
                 expr ldA, expr ldB, expr ldC,
                 expr offsetA, expr offsetB, expr offsetC,
                 expr transposeA, expr transposeB)
{
    if (A.get_location() != cuda_ast::memory_location::global ||
        B.get_location() != cuda_ast::memory_location::global ||
        C.get_location() != cuda_ast::memory_location::global) {
        ERROR("Buffers must be on GPU global memory", true);
    }
    std::string fname;
    expr alpha_expr;
    expr beta_expr;
    if (A.get_elements_type() == p_float32 &&
        B.get_elements_type() == p_float32 &&
        C.get_elements_type() == p_float32) {
        fname = "tiramisu_cublas_sgemm";
        alpha_expr = cast(p_float32, alpha);
        beta_expr = cast(p_float32, beta);
    } else if (A.get_elements_type() == p_float64 &&
               B.get_elements_type() == p_float64 &&
               C.get_elements_type() == p_float64) {
        fname = "tiramisu_cublas_dgemm";
        alpha_expr = cast(p_float64, alpha);
        beta_expr = cast(p_float64, beta);
    } else {
        ERROR("All input buffers should be of same type and either p_float32 or p_float64", true);
    }
    return expr(o_call, fname,
            {
                var(p_void_ptr, A.get_name()),
                var(p_void_ptr, B.get_name()),
                var(p_void_ptr, C.get_name()),
                cast(p_uint64, M), cast(p_uint64, N), cast(p_uint64, K),
                alpha_expr, beta_expr,
                cast(p_uint64, ldA), cast(p_uint64, ldB), cast(p_uint64, ldC),
                cast(p_uint64, offsetA), cast(p_uint64, offsetB), cast(p_uint64, offsetC),
                cast(p_boolean, transposeA), cast(p_boolean, transposeB)
            },
            tiramisu::p_uint8);
}

expr cuda_stream_synchronize()
{
    return expr(o_call, "tiramisu_cuda_stream_synchronize", {int32_t(0)}, tiramisu::p_int32);
}

extern "C"
int tiramisu_cblas_sgemm(float *A, float *B, float *C,
                          uint64_t M, uint64_t N, uint64_t K,
                          float alpha, float beta,
                          uint64_t ldA, uint64_t ldB, uint64_t ldC,
                          uint64_t offsetA, uint64_t offsetB, uint64_t offsetC,
                          bool transposeA, bool transposeB)
{
    // Default values for tight packing:
    if (ldA == 0) {
        ldA = transposeA ? M : K;
    }
    if (ldB == 0) {
        ldB = transposeB ? K : N;
    }
    if (ldC == 0) {
        ldC = N;
    }

    cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                M, N, K, alpha, A+offsetA, K, B+ offsetB, N, beta, C+ offsetC, N);
    return 0;
}

extern "C"
int tiramisu_cblas_dgemm(double *A, double *B, double *C,
                          uint64_t M, uint64_t N, uint64_t K,
                          double alpha, double beta,
                          uint64_t ldA, uint64_t ldB, uint64_t ldC,
                          uint64_t offsetA, uint64_t offsetB, uint64_t offsetC,
                          bool transposeA, bool transposeB)
{
    // Default values for tight packing:
    if (ldA == 0) {
        ldA = transposeA ? M : K;
    }
    if (ldB == 0) {
        ldB = transposeB ? K : N;
    }
    if (ldC == 0) {
        ldC = N;
    }

    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                M, N, K, alpha, A+offsetA, K, B+ offsetB, N, beta, C+ offsetC, N);
    return 0;
}

expr cblas_gemm_call(const buffer &A, const buffer &B, buffer &C,
                 expr M, expr N, expr K,
                 expr alpha, expr beta,
                 expr ldA, expr ldB, expr ldC,
                 expr offsetA, expr offsetB, expr offsetC,
                 expr transposeA, expr transposeB)
{
    std::string fname;
    expr alpha_expr;
    expr beta_expr;
    if (A.get_elements_type() == p_float32 &&
        B.get_elements_type() == p_float32 &&
        C.get_elements_type() == p_float32) {
        fname = "tiramisu_cblas_sgemm";
        alpha_expr = cast(p_float32, alpha);
        beta_expr = cast(p_float32, beta);
    } else if (A.get_elements_type() == p_float64 &&
               B.get_elements_type() == p_float64 &&
               C.get_elements_type() == p_float64) {
        fname = "tiramisu_cblas_dgemm";
        alpha_expr = cast(p_float64, alpha);
        beta_expr = cast(p_float64, beta);
    } else {
        ERROR("All input buffers should be of same type and either p_float32 or p_float64", true);
    }
    return expr(o_call, fname,
            {
                var(p_void_ptr, A.get_name()),
                var(p_void_ptr, B.get_name()),
                var(p_void_ptr, C.get_name()),
                cast(p_uint64, M), cast(p_uint64, N), cast(p_uint64, K),
                alpha_expr, beta_expr,
                cast(p_uint64, ldA), cast(p_uint64, ldB), cast(p_uint64, ldC),
                cast(p_uint64, offsetA), cast(p_uint64, offsetB), cast(p_uint64, offsetC),
                cast(p_boolean, transposeA), cast(p_boolean, transposeB)
            },
            tiramisu::p_uint8);
}

}
<|endoftext|>


<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017-2020 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "internal.h"

using namespace lcb::trace;

LIBCOUCHBASE_API lcbtrace_TRACER *lcbtrace_new(lcb_INSTANCE *instance, uint64_t flags)
{
    switch (flags) {
        case LCBTRACE_F_THRESHOLD:
            if (nullptr == instance) {
                return nullptr;
            }
            return (new ThresholdLoggingTracer(instance))->wrap();
        case LCBTRACE_F_EXTERNAL: {
            lcbtrace_TRACER *retval = new lcbtrace_TRACER;
            retval->flags = LCBTRACE_F_EXTERNAL;
            return retval;
        }
        default:
            return nullptr;
    }
}

LIBCOUCHBASE_API void lcbtrace_destroy(lcbtrace_TRACER *tracer)
{
    if (tracer && tracer->destructor) {
        tracer->destructor(tracer);
    }
}

LIBCOUCHBASE_API
lcbtrace_SPAN *lcbtrace_span_start(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace_REF *ref)
{
    lcbtrace_REF_TYPE type = LCBTRACE_REF_NONE;
    lcbtrace_SPAN *other = nullptr;
    if (ref) {
        type = ref->type;
        other = ref->span;
    }
    return new Span(tracer, opname, start, type, other, nullptr);
}

LIBCOUCHBASE_API
lcb_STATUS lcbtrace_span_wrap(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, void *external_span,
                              lcbtrace_SPAN **lcbspan)
{
    if (nullptr == *lcbspan && nullptr != external_span && nullptr != tracer && tracer->version == 1) {
        *lcbspan = new Span(tracer, opname, start, LCBTRACE_REF_NONE, nullptr, external_span);
        return LCB_SUCCESS;
    }
    return LCB_ERR_INVALID_ARGUMENT;
}

LIBCOUCHBASE_API
lcbtrace_TRACER *lcb_get_tracer(lcb_INSTANCE *instance)
{
    return (instance && instance->settings) ? instance->settings->tracer : nullptr;
}

LIBCOUCHBASE_API
void lcb_set_tracer(lcb_INSTANCE *instance, lcbtrace_TRACER *tracer)
{
    // TODO: this leaks the original one in the instance, _if_ it is
    // the default ThresholdLoggingTracer
    if (instance && instance->settings) {
        instance->settings->tracer = tracer;
    }
}

void lcbtrace_span_add_host_and_port(lcbtrace_SPAN *span, lcbio_CONNINFO *info)
{
    if (span) {
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_LOCAL_ADDRESS, info->ep_local.host);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_LOCAL_PORT, info->ep_local.port);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_PEER_ADDRESS, info->ep_remote.host);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_PEER_PORT, info->ep_remote.port);
    }
}

const char *dur_level_to_string(lcb_DURABILITY_LEVEL dur_level)
{
    switch (dur_level) {
        case LCB_DURABILITYLEVEL_NONE:
            return "none";
        case LCB_DURABILITYLEVEL_MAJORITY:
            return "majority";
        case LCB_DURABILITYLEVEL_MAJORITY_AND_PERSIST_TO_ACTIVE:
            return "majority_and_persist_to_active";
        case LCB_DURABILITYLEVEL_PERSIST_TO_MAJORITY:
            return "persist_to_majority";
        default:
            return "unknown";
    }
}
<commit_msg>CCBC-1479: initialize fields of custom tracer struct<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017-2020 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "internal.h"

using namespace lcb::trace;

LIBCOUCHBASE_API lcbtrace_TRACER *lcbtrace_new(lcb_INSTANCE *instance, uint64_t flags)
{
    switch (flags) {
        case LCBTRACE_F_THRESHOLD:
            if (nullptr == instance) {
                return nullptr;
            }
            return (new ThresholdLoggingTracer(instance))->wrap();
        case LCBTRACE_F_EXTERNAL: {
            lcbtrace_TRACER *retval = new lcbtrace_TRACER;
            retval->version = 0;
            retval->flags = LCBTRACE_F_EXTERNAL;
            retval->cookie = nullptr;
            retval->destructor = nullptr;
            retval->v.v0.report = nullptr;
            retval->v.v1.start_span = nullptr;
            retval->v.v1.end_span = nullptr;
            retval->v.v1.destroy_span = nullptr;
            retval->v.v1.add_tag_string = nullptr;
            retval->v.v1.add_tag_uint64 = nullptr;
            return retval;
        }
        default:
            return nullptr;
    }
}

LIBCOUCHBASE_API void lcbtrace_destroy(lcbtrace_TRACER *tracer)
{
    if (tracer && tracer->destructor) {
        tracer->destructor(tracer);
    }
}

LIBCOUCHBASE_API
lcbtrace_SPAN *lcbtrace_span_start(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace_REF *ref)
{
    lcbtrace_REF_TYPE type = LCBTRACE_REF_NONE;
    lcbtrace_SPAN *other = nullptr;
    if (ref) {
        type = ref->type;
        other = ref->span;
    }
    return new Span(tracer, opname, start, type, other, nullptr);
}

LIBCOUCHBASE_API
lcb_STATUS lcbtrace_span_wrap(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, void *external_span,
                              lcbtrace_SPAN **lcbspan)
{
    if (nullptr == *lcbspan && nullptr != external_span && nullptr != tracer && tracer->version == 1) {
        *lcbspan = new Span(tracer, opname, start, LCBTRACE_REF_NONE, nullptr, external_span);
        return LCB_SUCCESS;
    }
    return LCB_ERR_INVALID_ARGUMENT;
}

LIBCOUCHBASE_API
lcbtrace_TRACER *lcb_get_tracer(lcb_INSTANCE *instance)
{
    return (instance && instance->settings) ? instance->settings->tracer : nullptr;
}

LIBCOUCHBASE_API
void lcb_set_tracer(lcb_INSTANCE *instance, lcbtrace_TRACER *tracer)
{
    // TODO: this leaks the original one in the instance, _if_ it is
    // the default ThresholdLoggingTracer
    if (instance && instance->settings) {
        instance->settings->tracer = tracer;
    }
}

void lcbtrace_span_add_host_and_port(lcbtrace_SPAN *span, lcbio_CONNINFO *info)
{
    if (span) {
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_LOCAL_ADDRESS, info->ep_local.host);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_LOCAL_PORT, info->ep_local.port);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_PEER_ADDRESS, info->ep_remote.host);
        lcbtrace_span_add_tag_str_nocopy(span, LCBTRACE_TAG_PEER_PORT, info->ep_remote.port);
    }
}

const char *dur_level_to_string(lcb_DURABILITY_LEVEL dur_level)
{
    switch (dur_level) {
        case LCB_DURABILITYLEVEL_NONE:
            return "none";
        case LCB_DURABILITYLEVEL_MAJORITY:
            return "majority";
        case LCB_DURABILITYLEVEL_MAJORITY_AND_PERSIST_TO_ACTIVE:
            return "majority_and_persist_to_active";
        case LCB_DURABILITYLEVEL_PERSIST_TO_MAJORITY:
            return "persist_to_majority";
        default:
            return "unknown";
    }
}
<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "transcodeagent.hh"

#include "sdp-modifier.hh"

static MSList *makeSupportedAudioPayloadList(){
	/* in mediastreamer2, we use normal_bitrate as an IP bitrate, not codec bitrate*/
	payload_type_speex_nb.normal_bitrate=25000;
	payload_type_speex_wb.normal_bitrate=42000;
	payload_type_speex_nb.recv_fmtp=(char *)"vbr=1";

	payload_type_set_number(&payload_type_pcmu8000,0);
	payload_type_set_number(&payload_type_pcma8000,8);
	payload_type_set_number(&payload_type_gsm,3);
	payload_type_set_number(&payload_type_speex_nb,-1);
	payload_type_set_number(&payload_type_speex_wb,-1);
	payload_type_set_number(&payload_type_amr,-1);
	MSList *l=ms_list_append(NULL,&payload_type_pcmu8000);
	l=ms_list_append(l,&payload_type_pcma8000);
	l=ms_list_append(l,&payload_type_gsm);
	l=ms_list_append(l,&payload_type_speex_nb);
	l=ms_list_append(l,&payload_type_speex_wb);
	l=ms_list_append(l,&payload_type_amr);
	return l;
}

TranscodeAgent::TranscodeAgent(su_root_t *root, const char *locaddr, int port) :
	Agent(root,locaddr,port){

	mTicker=ms_ticker_new();
	mSupportedAudioPayloads=makeSupportedAudioPayloadList();
}

TranscodeAgent::~TranscodeAgent(){
	ms_ticker_destroy(mTicker);
}

bool TranscodeAgent::processSipInfo(CallContext *c, msg_t *msg, sip_t *sip){
	sip_payload_t *payload=sip->sip_payload;
	if (payload!=NULL && payload->pl_data!=NULL) {
		if (sip->sip_content_type!=NULL &&
		    strcasecmp(sip->sip_content_type->c_subtype,"dtmf-relay")==0){
			c->playTone (sip);
			nta_msg_treply(mAgent,msg,200,NULL,TAG_END());
			return true;
		}
	}
	return false;
}

const PayloadType *findPt(const MSList *l, const char *mime, int rate){
	for(;l!=NULL;l=l->next){
		const PayloadType *pt=(PayloadType*)l->data;
		if (pt->clock_rate==rate && strcasecmp(mime,pt->mime_type)==0)
			return pt;
	}
	return NULL;
}

MSList *TranscodeAgent::normalizePayloads(MSList *l){
	MSList *it;
	for(it=l;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)l->data;
		if (pt->normal_bitrate==0){
			const PayloadType *refpt=findPt(mSupportedAudioPayloads,pt->mime_type,pt->clock_rate);
			if (refpt && refpt->normal_bitrate>0){
				ms_message("Using %s at bitrate %i",pt->mime_type,refpt->normal_bitrate);
				pt->normal_bitrate=refpt->normal_bitrate;
			}
		}
	}
	return l;
}

void TranscodeAgent::processNewInvite(CallContext *c, msg_t *msg, sip_t *sip){
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(c->getHome(), sip);
	c->prepare(sip);
	c->setInitialOffer (m->readPayloads ());
	m->getAudioIpPort (&addr,&port);
	c->getFrontSide()->setRemoteAddr(addr.c_str(),port);
	port=c->getBackSide()->getAudioPort();
	m->changeAudioIpPort(getLocAddr().c_str(),port);
	m->appendNewPayloadsAndRemoveUnsupported(mSupportedAudioPayloads);
	m->update(msg,sip);
	//be in the record-route
	addRecordRoute(c->getHome(),msg,sip);
	c->storeNewInvite (msg);
	delete m;
}

int TranscodeAgent::onRequest(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_request->rq_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))==NULL){
			c=new CallContext(sip);
			mCalls.store(c);
			processNewInvite(c,msg,sip);
		}else{
			if (c->isNewInvite(sip)){
				processNewInvite(c,msg,sip);
			}else{
				msg=msg_copy(c->getLastForwardedInvite ());
				sip=(sip_t*)msg_object(msg);
				LOGD("Forwarding invite retransmission");
			}
		}
		forwardRequest (msg,sip);
	}else{
		 if (sip->sip_request->rq_method==sip_method_info){
			 if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				if (processSipInfo(c,msg,sip))
					 goto end;
			}
		 }

		//all other requests go through

		if (sip->sip_request->rq_method==sip_method_bye){
			if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				mCalls.remove(c);
				delete c;
			}
		}
		forwardRequest(msg,sip);
	}
	end:
	return 0;
}

void TranscodeAgent::process200OkforInvite(CallContext *ctx, msg_t *msg, sip_t *sip){
	LOGD("Processing 200 Ok");
	const MSList *ioffer=ctx->getInitialOffer ();
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(ctx->getHome(), sip);

	if (ctx->isJoined()) ctx->unjoin();

	m->getAudioIpPort (&addr,&port);
	ctx->getBackSide()->setRemoteAddr(addr.c_str(),port);
	m->changeAudioIpPort (getLocAddr().c_str(),ctx->getFrontSide()->getAudioPort());

	MSList *answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in 200Ok");
		delete m;
		return;
	}
	MSList *common=SdpModifier::findCommon (mSupportedAudioPayloads,ioffer);
	if (common!=NULL){
		m->appendNewPayloadsAndRemoveUnsupported(common);
		ms_list_for_each(common,(void(*)(void*))payload_type_destroy);
		ms_list_free(common);
	}
	m->update(msg,sip);
	ctx->storeNewResponse (msg);
	ctx->getBackSide ()->assignPayloads (answer);
	ms_list_free(answer);
	// read the modified answer to get payload list in right order:
	answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in forwarded 200Ok");
		delete m;
		return;
	}
	ctx->getFrontSide ()->assignPayloads (answer);
	ms_list_free(answer);
	ctx->join(mTicker);

	delete m;
}

static bool isEarlyMedia(sip_t *sip){
	if (sip->sip_status->st_status==180 || sip->sip_status->st_status==183){
		sip_payload_t *payload=sip->sip_payload;
		//TODO: should check if it is application/sdp
		return payload!=NULL;
	}
	return false;
}

int TranscodeAgent::onResponse(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_cseq && sip->sip_cseq->cs_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
			if (sip->sip_status->st_status==200 && c->isNew200Ok(sip)){
				process200OkforInvite (c,msg,sip);
			}else if (isEarlyMedia(sip) && c->isNewEarlyMedia (sip)){
				process200OkforInvite (c,msg,sip);
			}else if (sip->sip_status->st_status==200 || isEarlyMedia(sip)){
				LOGD("This is a 200 or 183  retransmission");
				msg=msg_copy(c->getLastForwaredResponse ());
				sip=(sip_t*)msg_object (msg);
			}
		}
	}
	return forwardResponse (msg,sip);
}

void TranscodeAgent::idle(){
	mCalls.dump();
	mCalls.removeInactives();
}
<commit_msg>remove speex wb temporarily<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "transcodeagent.hh"

#include "sdp-modifier.hh"

static MSList *makeSupportedAudioPayloadList(){
	/* in mediastreamer2, we use normal_bitrate as an IP bitrate, not codec bitrate*/
	payload_type_speex_nb.normal_bitrate=25000;
	payload_type_speex_wb.normal_bitrate=42000;
	payload_type_speex_nb.recv_fmtp=(char *)"vbr=1";

	payload_type_set_number(&payload_type_pcmu8000,0);
	payload_type_set_number(&payload_type_pcma8000,8);
	payload_type_set_number(&payload_type_gsm,3);
	payload_type_set_number(&payload_type_speex_nb,-1);
	payload_type_set_number(&payload_type_speex_wb,-1);
	payload_type_set_number(&payload_type_amr,-1);
	MSList *l=ms_list_append(NULL,&payload_type_pcmu8000);
	l=ms_list_append(l,&payload_type_pcma8000);
	l=ms_list_append(l,&payload_type_gsm);
	l=ms_list_append(l,&payload_type_speex_nb);
	//l=ms_list_append(l,&payload_type_speex_wb);
	l=ms_list_append(l,&payload_type_amr);
	return l;
}

TranscodeAgent::TranscodeAgent(su_root_t *root, const char *locaddr, int port) :
	Agent(root,locaddr,port){

	mTicker=ms_ticker_new();
	mSupportedAudioPayloads=makeSupportedAudioPayloadList();
}

TranscodeAgent::~TranscodeAgent(){
	ms_ticker_destroy(mTicker);
}

bool TranscodeAgent::processSipInfo(CallContext *c, msg_t *msg, sip_t *sip){
	sip_payload_t *payload=sip->sip_payload;
	if (payload!=NULL && payload->pl_data!=NULL) {
		if (sip->sip_content_type!=NULL &&
		    strcasecmp(sip->sip_content_type->c_subtype,"dtmf-relay")==0){
			c->playTone (sip);
			nta_msg_treply(mAgent,msg,200,NULL,TAG_END());
			return true;
		}
	}
	return false;
}

const PayloadType *findPt(const MSList *l, const char *mime, int rate){
	for(;l!=NULL;l=l->next){
		const PayloadType *pt=(PayloadType*)l->data;
		if (pt->clock_rate==rate && strcasecmp(mime,pt->mime_type)==0)
			return pt;
	}
	return NULL;
}

MSList *TranscodeAgent::normalizePayloads(MSList *l){
	MSList *it;
	for(it=l;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)l->data;
		if (pt->normal_bitrate==0){
			const PayloadType *refpt=findPt(mSupportedAudioPayloads,pt->mime_type,pt->clock_rate);
			if (refpt && refpt->normal_bitrate>0){
				ms_message("Using %s at bitrate %i",pt->mime_type,refpt->normal_bitrate);
				pt->normal_bitrate=refpt->normal_bitrate;
			}
		}
	}
	return l;
}

void TranscodeAgent::processNewInvite(CallContext *c, msg_t *msg, sip_t *sip){
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(c->getHome(), sip);
	c->prepare(sip);
	c->setInitialOffer (m->readPayloads ());
	m->getAudioIpPort (&addr,&port);
	c->getFrontSide()->setRemoteAddr(addr.c_str(),port);
	port=c->getBackSide()->getAudioPort();
	m->changeAudioIpPort(getLocAddr().c_str(),port);
	m->appendNewPayloadsAndRemoveUnsupported(mSupportedAudioPayloads);
	m->update(msg,sip);
	//be in the record-route
	addRecordRoute(c->getHome(),msg,sip);
	c->storeNewInvite (msg);
	delete m;
}

int TranscodeAgent::onRequest(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_request->rq_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))==NULL){
			c=new CallContext(sip);
			mCalls.store(c);
			processNewInvite(c,msg,sip);
		}else{
			if (c->isNewInvite(sip)){
				processNewInvite(c,msg,sip);
			}else{
				msg=msg_copy(c->getLastForwardedInvite ());
				sip=(sip_t*)msg_object(msg);
				LOGD("Forwarding invite retransmission");
			}
		}
		forwardRequest (msg,sip);
	}else{
		 if (sip->sip_request->rq_method==sip_method_info){
			 if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				if (processSipInfo(c,msg,sip))
					 goto end;
			}
		 }

		//all other requests go through

		if (sip->sip_request->rq_method==sip_method_bye){
			if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				mCalls.remove(c);
				delete c;
			}
		}
		forwardRequest(msg,sip);
	}
	end:
	return 0;
}

void TranscodeAgent::process200OkforInvite(CallContext *ctx, msg_t *msg, sip_t *sip){
	LOGD("Processing 200 Ok");
	const MSList *ioffer=ctx->getInitialOffer ();
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(ctx->getHome(), sip);

	if (ctx->isJoined()) ctx->unjoin();

	m->getAudioIpPort (&addr,&port);
	ctx->getBackSide()->setRemoteAddr(addr.c_str(),port);
	m->changeAudioIpPort (getLocAddr().c_str(),ctx->getFrontSide()->getAudioPort());

	MSList *answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in 200Ok");
		delete m;
		return;
	}
	MSList *common=SdpModifier::findCommon (mSupportedAudioPayloads,ioffer);
	if (common!=NULL){
		m->appendNewPayloadsAndRemoveUnsupported(common);
		ms_list_for_each(common,(void(*)(void*))payload_type_destroy);
		ms_list_free(common);
	}
	m->update(msg,sip);
	ctx->storeNewResponse (msg);
	ctx->getBackSide ()->assignPayloads (answer);
	ms_list_free(answer);
	// read the modified answer to get payload list in right order:
	answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in forwarded 200Ok");
		delete m;
		return;
	}
	ctx->getFrontSide ()->assignPayloads (answer);
	ms_list_free(answer);
	ctx->join(mTicker);

	delete m;
}

static bool isEarlyMedia(sip_t *sip){
	if (sip->sip_status->st_status==180 || sip->sip_status->st_status==183){
		sip_payload_t *payload=sip->sip_payload;
		//TODO: should check if it is application/sdp
		return payload!=NULL;
	}
	return false;
}

int TranscodeAgent::onResponse(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_cseq && sip->sip_cseq->cs_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
			if (sip->sip_status->st_status==200 && c->isNew200Ok(sip)){
				process200OkforInvite (c,msg,sip);
			}else if (isEarlyMedia(sip) && c->isNewEarlyMedia (sip)){
				process200OkforInvite (c,msg,sip);
			}else if (sip->sip_status->st_status==200 || isEarlyMedia(sip)){
				LOGD("This is a 200 or 183  retransmission");
				msg=msg_copy(c->getLastForwaredResponse ());
				sip=(sip_t*)msg_object (msg);
			}
		}
	}
	return forwardResponse (msg,sip);
}

void TranscodeAgent::idle(){
	mCalls.dump();
	mCalls.removeInactives();
}
<|endoftext|>


<commit_before>// maze.cpp
// 2D maze data & routines

// Copyright 2015 Matthew Chandler

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <string>
#include <stdexcept>

#include <gtkmm/button.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/grid.h>
#include <gtkmm/label.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/separator.h>

#include "maze.hpp"

Maze::Maze(const unsigned int width, const unsigned int height):
    _grid_width(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _grid_height(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _room_attempts(Gtk::Adjustment::create(25, 0.0, 10000.0, 1.0)),
    _wall_rm_attempts(Gtk::Adjustment::create(100, 0.0, 10000.0, 1.0))
{
    set_title("MazeGen 2D"); // TODO: get from config file
    set_default_size(1024, 600);

    Gtk::Grid * layout = Gtk::manage(new Gtk::Grid);
    layout->set_border_width(3);
    layout->set_row_spacing(3);
    layout->set_column_spacing(5);
    add(*layout);

    layout->attach(_draw_area, 0, 0, 1, 10);
    _draw_area.set_hexpand();
    _draw_area.set_vexpand();
    _draw_area.signal_draw().connect(sigc::bind(sigc::mem_fun(*this, &Maze::draw), 0, 0));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid width")), 1, 0, 1, 1);
    layout->attach(_grid_width, 2, 0, 1, 1);
    _grid_width.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid height")), 1, 1, 1, 1);
    layout->attach(_grid_height, 2, 1, 1, 1);
    _grid_height.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 2, 2, 1);

    layout->attach(*Gtk::manage(new Gtk::Label("Maze algorithm")), 1, 3, 1, 1);
    layout->attach(_mazegen, 2, 3, 1, 1);
    _mazegen.append("Depth First Search");
    _mazegen.append("Prim's Algorithm");
    _mazegen.append("Kruskal's Algorithm");
    _mazegen.set_active_text("Depth First Search");
    _mazegen.signal_changed().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Room attempts")), 1, 4, 1, 1);
    layout->attach(_room_attempts, 2, 4, 1, 1);
    _room_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Wall removal attempts")), 1, 5, 1, 1);
    layout->attach(_wall_rm_attempts, 2, 5, 1, 1);
    _wall_rm_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 6, 2, 1);

    Gtk::Button * regen_butt = Gtk::manage(new Gtk::Button("Regenerate"));
    layout->attach(*regen_butt, 1, 7, 2, 1);
    regen_butt->set_hexpand(false);
    regen_butt->set_halign(Gtk::ALIGN_CENTER);
    regen_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::regen));

    Gtk::Label * spacer = Gtk::manage(new Gtk::Label);
    spacer->set_vexpand(true);
    layout->attach(*spacer, 1, 8, 2, 1);

    Gtk::Grid * button_box = Gtk::manage(new Gtk::Grid);
    layout->attach(*button_box, 1, 9, 2, 1);
    button_box->set_column_spacing(3);
    button_box->set_hexpand(false);

    Gtk::Label * button_spacer = Gtk::manage(new Gtk::Label);
    button_spacer->set_hexpand(true);
    button_box->attach(*button_spacer, 0, 0, 1, 1);

    Gtk::Button * save_butt = Gtk::manage(new Gtk::Button("Save"));
    button_box->attach(*save_butt, 1, 0, 1, 1);
    save_butt->set_hexpand(false);
    save_butt->set_halign(Gtk::ALIGN_CENTER);
    save_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::save));

    Gtk::Button * close_butt = Gtk::manage(new Gtk::Button("Close"));
    button_box->attach(*close_butt, 2, 0, 1, 1);
    close_butt->set_hexpand(false);
    close_butt->set_halign(Gtk::ALIGN_CENTER);
    close_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::hide));

    show_all_children();
    regen();
}

bool Maze::draw(const Cairo::RefPtr<Cairo::Context> & cr, const unsigned int width, const unsigned int height)
{
    double width_d, height_d;

    if(width == 0)
        width_d = (double)_draw_area.get_allocated_width();
    else
        width_d = (double)width;

    if(height == 0)
        height_d = (double)_draw_area.get_allocated_height();
    else
        height_d = (double)height;

    // set background
    cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
    cr->rectangle(0.0, 0.0, width_d, height_d);
    cr->fill_preserve();

    // set line properties
    cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
    cr->set_line_width(2.0);

    cr->stroke();

    double cell_scale_x = width_d / (double)_grid.grid[0].size();
    double cell_scale_y = height_d / (double)_grid.grid.size();

    // draw maze cells
    for(size_t row = 0; row < _grid.grid.size(); ++row)
    {
        for(size_t col = 0; col < _grid.grid[row].size(); ++col)
        {
            sf::Vector2f ul(cell_scale_x * (double)col, cell_scale_y * (double)row);

            if(_grid.grid[row][col].walls[UP])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x + cell_scale_x, ul.y);
            }
            if(_grid.grid[row][col].walls[LEFT])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x, ul.y + cell_scale_y);
            }
        }
    }

    cr->stroke();

    return true;
};

void Maze::regen()
{
    unsigned int grid_width = _grid_width.get_value_as_int();
    unsigned int grid_height = _grid_height.get_value_as_int();
    unsigned int room_attempts = _room_attempts.get_value_as_int();
    unsigned int wall_rm_attempts = _wall_rm_attempts.get_value_as_int();

    Grid::Mazegen_alg mazegen;
    std::string mazegen_txt = _mazegen.get_active_text();
    if(mazegen_txt == "Depth First Search")
        mazegen = Grid::MAZEGEN_DFS;
    else if(mazegen_txt == "Prim's Algorithm")
        mazegen = Grid::MAZEGEN_PRIM;
    else if(mazegen_txt == "Kruskal's Algorithm")
        mazegen = Grid::MAZEGEN_KRUSKAL;
    else
        throw std::invalid_argument(std::string("Unknown maze algorithm: ") + mazegen_txt);

    _grid.init(grid_width, grid_height, mazegen, room_attempts, wall_rm_attempts);

    _draw_area.queue_draw();
}

void Maze::save()
{
    // get image size from user
    Gtk::Dialog size_dialog("Image Size", *this, true);
    size_dialog.add_button("OK", Gtk::RESPONSE_OK);
    size_dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);

    Gtk::Grid size_layout;
    size_layout.set_border_width(3);
    size_layout.set_row_spacing(3);
    size_layout.set_column_spacing(3);
    size_dialog.get_content_area()->add(size_layout);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Width:")), 0, 0, 1, 1);
    Gtk::SpinButton width_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(width_spin, 1, 0, 1, 1);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Height:")), 0, 1, 1, 1);
    Gtk::SpinButton height_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(height_spin, 1, 1, 1, 1);

    size_dialog.show_all_children();

    if(size_dialog.run() != Gtk::RESPONSE_OK)
        return;

    size_dialog.hide();

    Gtk::FileChooserDialog chooser(*this, "Save to", Gtk::FILE_CHOOSER_ACTION_SAVE);
    chooser.set_modal(true);
    chooser.set_current_folder(".");
    chooser.set_select_multiple(false);
    chooser.set_do_overwrite_confirmation(true);
    chooser.add_button("Cancel", Gtk::RESPONSE_CANCEL);
    chooser.add_button("Save", Gtk::RESPONSE_OK);

    for(const auto & format: Gdk::Pixbuf::get_formats())
    {
        if(!format.is_writable())
            continue;

        Glib::RefPtr<Gtk::FileFilter> image_type = Gtk::FileFilter::create();
        image_type->set_name(format.get_name());

        for(const auto & mimetype: format.get_mime_types())
            image_type->add_mime_type(mimetype);

        chooser.add_filter(image_type);

        if(format.get_name() == "png")
            chooser.set_filter(image_type);
    }

    if(chooser.run() != Gtk::RESPONSE_OK)
        return;

    chooser.hide();

    unsigned int width = width_spin.get_value_as_int();
    unsigned int height = height_spin.get_value_as_int();

    Cairo::RefPtr<Cairo::ImageSurface> render_target = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
    draw(Cairo::Context::create(render_target), width, height);

    try
    {
        Gdk::Pixbuf::create(render_target, 0, 0, width, height)->
            save(chooser.get_filename(), chooser.get_filter()->get_name());
    }
    catch(const Glib::Error & e)
    {
        Gtk::MessageDialog error_box(*this, std::string("Error saving to ") + chooser.get_filename(),
            false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_box.set_secondary_text(e.what());
        error_box.run();
    }
}
<commit_msg>tweak mazegen<commit_after>// maze.cpp
// 2D maze data & routines

// Copyright 2015 Matthew Chandler

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <string>
#include <stdexcept>

#include <gtkmm/button.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/grid.h>
#include <gtkmm/label.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/separator.h>

#include "maze.hpp"

Maze::Maze(const unsigned int width, const unsigned int height):
    _grid_width(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _grid_height(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _room_attempts(Gtk::Adjustment::create(25, 0.0, 10000.0, 1.0)),
    _wall_rm_attempts(Gtk::Adjustment::create(100, 0.0, 10000.0, 1.0))
{
    set_title("MazeGen 2D"); // TODO: get from config file
    set_default_size(1024, 600);

    Gtk::Grid * layout = Gtk::manage(new Gtk::Grid);
    layout->set_border_width(3);
    layout->set_row_spacing(3);
    layout->set_column_spacing(5);
    add(*layout);

    layout->attach(_draw_area, 0, 0, 1, 10);
    _draw_area.set_hexpand();
    _draw_area.set_vexpand();
    _draw_area.signal_draw().connect(sigc::bind<const unsigned int, const unsigned int>(sigc::mem_fun(*this, &Maze::draw), 0, 0));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid width")), 1, 0, 1, 1);
    layout->attach(_grid_width, 2, 0, 1, 1);
    _grid_width.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid height")), 1, 1, 1, 1);
    layout->attach(_grid_height, 2, 1, 1, 1);
    _grid_height.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 2, 2, 1);

    layout->attach(*Gtk::manage(new Gtk::Label("Maze algorithm")), 1, 3, 1, 1);
    layout->attach(_mazegen, 2, 3, 1, 1);
    _mazegen.append("Depth First Search");
    _mazegen.append("Prim's Algorithm");
    _mazegen.append("Kruskal's Algorithm");
    _mazegen.set_active_text("Depth First Search");
    _mazegen.signal_changed().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Room attempts")), 1, 4, 1, 1);
    layout->attach(_room_attempts, 2, 4, 1, 1);
    _room_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Wall removal attempts")), 1, 5, 1, 1);
    layout->attach(_wall_rm_attempts, 2, 5, 1, 1);
    _wall_rm_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 6, 2, 1);

    Gtk::Button * regen_butt = Gtk::manage(new Gtk::Button("Regenerate"));
    layout->attach(*regen_butt, 1, 7, 2, 1);
    regen_butt->set_hexpand(false);
    regen_butt->set_halign(Gtk::ALIGN_CENTER);
    regen_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::regen));

    Gtk::Label * spacer = Gtk::manage(new Gtk::Label);
    spacer->set_vexpand(true);
    layout->attach(*spacer, 1, 8, 2, 1);

    Gtk::Grid * button_box = Gtk::manage(new Gtk::Grid);
    layout->attach(*button_box, 1, 9, 2, 1);
    button_box->set_column_spacing(3);
    button_box->set_hexpand(false);

    Gtk::Label * button_spacer = Gtk::manage(new Gtk::Label);
    button_spacer->set_hexpand(true);
    button_box->attach(*button_spacer, 0, 0, 1, 1);

    Gtk::Button * save_butt = Gtk::manage(new Gtk::Button("Save"));
    button_box->attach(*save_butt, 1, 0, 1, 1);
    save_butt->set_hexpand(false);
    save_butt->set_halign(Gtk::ALIGN_CENTER);
    save_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::save));

    Gtk::Button * close_butt = Gtk::manage(new Gtk::Button("Close"));
    button_box->attach(*close_butt, 2, 0, 1, 1);
    close_butt->set_hexpand(false);
    close_butt->set_halign(Gtk::ALIGN_CENTER);
    close_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::hide));

    show_all_children();
    regen();
}

bool Maze::draw(const Cairo::RefPtr<Cairo::Context> & cr, const unsigned int width, const unsigned int height)
{
    double width_d, height_d;

    if(width == 0)
        width_d = (double)_draw_area.get_allocated_width();
    else
        width_d = (double)width;

    if(height == 0)
        height_d = (double)_draw_area.get_allocated_height();
    else
        height_d = (double)height;

    // set background
    cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
    cr->rectangle(0.0, 0.0, width_d, height_d);
    cr->fill_preserve();

    // set line properties
    cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
    cr->set_line_width(2.0);

    cr->stroke();

    double cell_scale_x = width_d / (double)_grid.grid[0].size();
    double cell_scale_y = height_d / (double)_grid.grid.size();

    // draw maze cells
    for(size_t row = 0; row < _grid.grid.size(); ++row)
    {
        for(size_t col = 0; col < _grid.grid[row].size(); ++col)
        {
            sf::Vector2f ul(cell_scale_x * (double)col, cell_scale_y * (double)row);

            if(_grid.grid[row][col].walls[UP])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x + cell_scale_x, ul.y);
            }
            if(_grid.grid[row][col].walls[LEFT])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x, ul.y + cell_scale_y);
            }
        }
    }

    cr->stroke();

    return true;
};

void Maze::regen()
{
    unsigned int grid_width = _grid_width.get_value_as_int();
    unsigned int grid_height = _grid_height.get_value_as_int();
    unsigned int room_attempts = _room_attempts.get_value_as_int();
    unsigned int wall_rm_attempts = _wall_rm_attempts.get_value_as_int();

    Grid::Mazegen_alg mazegen;
    std::string mazegen_txt = _mazegen.get_active_text();
    if(mazegen_txt == "Depth First Search")
        mazegen = Grid::MAZEGEN_DFS;
    else if(mazegen_txt == "Prim's Algorithm")
        mazegen = Grid::MAZEGEN_PRIM;
    else if(mazegen_txt == "Kruskal's Algorithm")
        mazegen = Grid::MAZEGEN_KRUSKAL;
    else
        throw std::invalid_argument(std::string("Unknown maze algorithm: ") + mazegen_txt);

    _grid.init(grid_width, grid_height, mazegen, room_attempts, wall_rm_attempts);

    _draw_area.queue_draw();
}

void Maze::save()
{
    // get image size from user
    Gtk::Dialog size_dialog("Image Size", *this, true);
    size_dialog.add_button("OK", Gtk::RESPONSE_OK);
    size_dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);

    Gtk::Grid size_layout;
    size_layout.set_border_width(3);
    size_layout.set_row_spacing(3);
    size_layout.set_column_spacing(3);
    size_dialog.get_content_area()->add(size_layout);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Width:")), 0, 0, 1, 1);
    Gtk::SpinButton width_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(width_spin, 1, 0, 1, 1);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Height:")), 0, 1, 1, 1);
    Gtk::SpinButton height_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(height_spin, 1, 1, 1, 1);

    size_dialog.show_all_children();

    if(size_dialog.run() != Gtk::RESPONSE_OK)
        return;

    size_dialog.hide();

    Gtk::FileChooserDialog chooser(*this, "Save to", Gtk::FILE_CHOOSER_ACTION_SAVE);
    chooser.set_modal(true);
    chooser.set_current_folder(".");
    chooser.set_select_multiple(false);
    chooser.set_do_overwrite_confirmation(true);
    chooser.add_button("Cancel", Gtk::RESPONSE_CANCEL);
    chooser.add_button("Save", Gtk::RESPONSE_OK);

    for(const auto & format: Gdk::Pixbuf::get_formats())
    {
        if(!format.is_writable())
            continue;

        Glib::RefPtr<Gtk::FileFilter> image_type = Gtk::FileFilter::create();
        image_type->set_name(format.get_name());

        for(const auto & mimetype: format.get_mime_types())
            image_type->add_mime_type(mimetype);

        chooser.add_filter(image_type);

        if(format.get_name() == "png")
            chooser.set_filter(image_type);
    }

    if(chooser.run() != Gtk::RESPONSE_OK)
        return;

    chooser.hide();

    unsigned int width = width_spin.get_value_as_int();
    unsigned int height = height_spin.get_value_as_int();

    Cairo::RefPtr<Cairo::ImageSurface> render_target = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
    draw(Cairo::Context::create(render_target), width, height);

    try
    {
        Gdk::Pixbuf::create(render_target, 0, 0, width, height)->
            save(chooser.get_filename(), chooser.get_filter()->get_name());
    }
    catch(const Glib::Error & e)
    {
        Gtk::MessageDialog error_box(*this, std::string("Error saving to ") + chooser.get_filename(),
            false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_box.set_secondary_text(e.what());
        error_box.run();
    }
}
<|endoftext|>


<commit_before>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                      */
/*                                                                                */
/**************************************************************************************/

#ifndef Object_INCLUDE_ONCE
#define Object_INCLUDE_ONCE

#include <vlCore/checks.hpp>
#include <vlCore/IMutex.hpp>
#include <string>

#if VL_DEBUG_LIVING_OBJECTS
  #include <set>
#endif

namespace vl
{
  template<class T> class ref;

  //------------------------------------------------------------------------------
  // Object
  //------------------------------------------------------------------------------
  /**
   * The base class for all the reference counted objects.
   * See also vl::ref.
  */
  class VLCORE_EXPORT Object
  {
  public:

    //! Returns the name of the class.
    virtual const char* className() { return "vl::Object"; }

    //! Constructor.
    Object()
    {
      VL_DEBUG_SET_OBJECT_NAME()
      mRefCountMutex = NULL;
      mReferenceCount = 0;
      mAutomaticDelete = true;
      // user data
      #if VL_ACTOR_USER_DATA
        mUserData = NULL;
      #endif
      #if VL_DEBUG_LIVING_OBJECTS
        debug_living_objects()->insert(this);
        // mDebug_LivingObjects.insert(this);
      #endif
    }

    //! Copy constructor: copies the name, ref count mutex and user data.
    Object(const Object& other)
    {
      // copy the name, the ref count mutex and the user data.
      mObjectName = other.mObjectName;
      mRefCountMutex = other.mRefCountMutex;
      #if VL_ACTOR_USER_DATA
        mUserData = other.mUserData;
      #endif

      // mReferenceCount and mAutomaticDelete are not copiable.
      mReferenceCount  = 0;
      mAutomaticDelete = true;

      // debug living object
      #if VL_DEBUG_LIVING_OBJECTS
        debug_living_objects()->insert(this);
      #endif
    }

    //! Copy operator: copies the object's name, ref count mutex and user data.
    Object& operator=(const Object& other)
    {
      // copy the name, the ref count mutex and the user data.
      mObjectName = other.mObjectName;
      mRefCountMutex = other.mRefCountMutex;
      #if VL_ACTOR_USER_DATA
        mUserData = other.mUserData;
      #endif

      // mReferenceCount and mAutomaticDelete are not copiable.
      // ...

      return *this;
    }

    //! The name of the object, by default set to the object's class name.
    const std::string& objectName() const { return mObjectName; }

    //! The name of the object, by default set to the object's class name.
    void setObjectName(const std::string& name) { mObjectName = name; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    void setRefCountMutex(IMutex* mutex) { mRefCountMutex = mutex; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    IMutex* refCountMutex() { return mRefCountMutex; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    const IMutex* refCountMutex() const { return mRefCountMutex; }

    //! Returns the number of references of an object.
    int referenceCount() const
    {
      return mReferenceCount;
    }

    //! Increments the reference count of an object.
    void incReference()
    {
      // Lock mutex
      if (refCountMutex())
        refCountMutex()->lock();

      ++mReferenceCount;

      // Unlock mutex
      if(refCountMutex())
        refCountMutex()->unlock();
    }

    //! Decrements the reference count of an object and deletes it if both automaticDelete() is \p true the count reaches 0.
    void decReference()
    {
      // Save local copy in case of deletion.
      IMutex* mutex = mRefCountMutex;

      // Lock mutex.
      if (mutex)
        mutex->lock();

      VL_CHECK(mReferenceCount)
      --mReferenceCount;
      if (mReferenceCount == 0 && automaticDelete())
        delete this;

      // Unlock mutex.
      if (mutex)
        mutex->unlock();
    }

    //! If set to true the Object is deleted when its reference count reaches 0
    void setAutomaticDelete(bool autodel_on) { mAutomaticDelete = autodel_on; }

    //! If set to true the Object is deleted when its reference count reaches 0
    bool automaticDelete() const { return mAutomaticDelete; }

    //! Casts an Object to the specified class.
    template<class T>
    T* as() { return dynamic_cast<T*>(this); }

    //! Casts an Object to the specified class.
    template<class T>
    const T* as() const { return dynamic_cast<const T*>(this); }

#if VL_OBJECT_USER_DATA
  public:
    void* userData() { return mUserData; }
    const void* userData() const { return mUserData; }
    void setUserData(void* user_data) { mUserData = user_data; }

  private:
    void* mUserData;
#endif

  protected:
    virtual ~Object();
    std::string mObjectName;

    IMutex* mRefCountMutex;
    int mReferenceCount;
    bool mAutomaticDelete;

  // debugging facilities

  public:
  #if VL_DEBUG_LIVING_OBJECTS
    static std::set< Object* >* mDebug_LivingObjects;
    static std::set< Object* >* debug_living_objects()
    {
      if (!mDebug_LivingObjects)
        mDebug_LivingObjects = new std::set< Object* >;
      return mDebug_LivingObjects;
    }
  #endif
  };
  //------------------------------------------------------------------------------
  // ref
  //------------------------------------------------------------------------------
  /**
   * The ref<> class is used to reference-count an Object.
   * When the last ref<> that points to an Object is deallocated also the pointed Object is deallocated.
  */
  template<class T>
  class ref
  {
  public:
    ref(T* object=NULL)
    {
      mObject = object;
      if (mObject)
        mObject->incReference();
    }
    ref(const ref& other)
    {
      mObject = NULL;
      *this = other;
    }
    template<class T2> ref(const ref<T2>& other)
    {
      mObject = NULL;
      *this = other;
    }
    ~ref()
    {
      if (mObject)
        mObject->decReference();
      mObject = NULL;
    }
    ref& operator=(const ref& other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other.get();
      return *this;
    }
    template<class T2> ref& operator=(const ref<T2>& other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other.get();
      return *this;
    }
    ref& operator=(T* other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other;
      return *this;
    }
    template<class T2> ref& operator=(T2* other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other;
      return *this;
    }
    void swap(ref& other)
    {
      T* tmp = other.get();
      other = mObject;
      mObject = tmp;
    }
    T* get() const { return mObject; }
    T* operator->() const { VL_CHECK(mObject); return mObject; }
    T& operator*() const { VL_CHECK(mObject); return *mObject; }
    bool operator<(const ref& other) const { return mObject < other.get(); }
    operator bool() const { return mObject != NULL; }

  protected:
    T* mObject;
  };
  // interaction with the other types
  template<class T1, class T2> inline bool operator==(const ref<T1> & o1, const ref<T2> & o2) { return o1.get() == o2.get(); }
  template<class T1, class T2> inline bool operator!=(const ref<T1> & o1, const ref<T2> & o2) { return o1.get() != o2.get(); }
  template<class T1, class T2> inline bool operator==(const ref<T1> & o1, T2 * o2) { return o1.get() == o2; }
  template<class T1, class T2> inline bool operator!=(const ref<T1> & o1, T2 * o2) { return o1.get() != o2; }
  template<class T1, class T2> inline bool operator==(T1 * o1, const ref<T2> & o2) { return o1 == o2.get(); }
  template<class T1, class T2> inline bool operator!=(T1 * o1, const ref<T2> & o2) { return o1 != o2.get(); }
}

#endif
<commit_msg>Fixed VL_ACTOR_USER_DATA incorrectly placed inside Object.hpp<commit_after>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                      */
/*                                                                                */
/**************************************************************************************/

#ifndef Object_INCLUDE_ONCE
#define Object_INCLUDE_ONCE

#include <vlCore/checks.hpp>
#include <vlCore/IMutex.hpp>
#include <string>

#if VL_DEBUG_LIVING_OBJECTS
  #include <set>
#endif

namespace vl
{
  template<class T> class ref;

  //------------------------------------------------------------------------------
  // Object
  //------------------------------------------------------------------------------
  /**
   * The base class for all the reference counted objects.
   * See also vl::ref.
  */
  class VLCORE_EXPORT Object
  {
  public:

    //! Returns the name of the class.
    virtual const char* className() { return "vl::Object"; }

    //! Constructor.
    Object()
    {
      VL_DEBUG_SET_OBJECT_NAME()
      mRefCountMutex = NULL;
      mReferenceCount = 0;
      mAutomaticDelete = true;
      // user data
      #if VL_OBJECT_USER_DATA
        mUserData = NULL;
      #endif
      #if VL_DEBUG_LIVING_OBJECTS
        debug_living_objects()->insert(this);
        // mDebug_LivingObjects.insert(this);
      #endif
    }

    //! Copy constructor: copies the name, ref count mutex and user data.
    Object(const Object& other)
    {
      // copy the name, the ref count mutex and the user data.
      mObjectName = other.mObjectName;
      mRefCountMutex = other.mRefCountMutex;
      #if VL_OBJECT_USER_DATA
        mUserData = other.mUserData;
      #endif

      // mReferenceCount and mAutomaticDelete are not copiable.
      mReferenceCount  = 0;
      mAutomaticDelete = true;

      // debug living object
      #if VL_DEBUG_LIVING_OBJECTS
        debug_living_objects()->insert(this);
      #endif
    }

    //! Copy operator: copies the object's name, ref count mutex and user data.
    Object& operator=(const Object& other)
    {
      // copy the name, the ref count mutex and the user data.
      mObjectName = other.mObjectName;
      mRefCountMutex = other.mRefCountMutex;
      #if VL_OBJECT_USER_DATA
        mUserData = other.mUserData;
      #endif

      // mReferenceCount and mAutomaticDelete are not copiable.
      // ...

      return *this;
    }

    //! The name of the object, by default set to the object's class name.
    const std::string& objectName() const { return mObjectName; }

    //! The name of the object, by default set to the object's class name.
    void setObjectName(const std::string& name) { mObjectName = name; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    void setRefCountMutex(IMutex* mutex) { mRefCountMutex = mutex; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    IMutex* refCountMutex() { return mRefCountMutex; }

    //! The mutex used to protect the reference counting of an Object across multiple threads.
    const IMutex* refCountMutex() const { return mRefCountMutex; }

    //! Returns the number of references of an object.
    int referenceCount() const
    {
      return mReferenceCount;
    }

    //! Increments the reference count of an object.
    void incReference()
    {
      // Lock mutex
      if (refCountMutex())
        refCountMutex()->lock();

      ++mReferenceCount;

      // Unlock mutex
      if(refCountMutex())
        refCountMutex()->unlock();
    }

    //! Decrements the reference count of an object and deletes it if both automaticDelete() is \p true the count reaches 0.
    void decReference()
    {
      // Save local copy in case of deletion.
      IMutex* mutex = mRefCountMutex;

      // Lock mutex.
      if (mutex)
        mutex->lock();

      VL_CHECK(mReferenceCount)
      --mReferenceCount;
      if (mReferenceCount == 0 && automaticDelete())
        delete this;

      // Unlock mutex.
      if (mutex)
        mutex->unlock();
    }

    //! If set to true the Object is deleted when its reference count reaches 0
    void setAutomaticDelete(bool autodel_on) { mAutomaticDelete = autodel_on; }

    //! If set to true the Object is deleted when its reference count reaches 0
    bool automaticDelete() const { return mAutomaticDelete; }

    //! Casts an Object to the specified class.
    template<class T>
    T* as() { return dynamic_cast<T*>(this); }

    //! Casts an Object to the specified class.
    template<class T>
    const T* as() const { return dynamic_cast<const T*>(this); }

#if VL_OBJECT_USER_DATA
  public:
    void* userData() { return mUserData; }
    const void* userData() const { return mUserData; }
    void setUserData(void* user_data) { mUserData = user_data; }

  private:
    void* mUserData;
#endif

  protected:
    virtual ~Object();
    std::string mObjectName;

    IMutex* mRefCountMutex;
    int mReferenceCount;
    bool mAutomaticDelete;

  // debugging facilities

  public:
  #if VL_DEBUG_LIVING_OBJECTS
    static std::set< Object* >* mDebug_LivingObjects;
    static std::set< Object* >* debug_living_objects()
    {
      if (!mDebug_LivingObjects)
        mDebug_LivingObjects = new std::set< Object* >;
      return mDebug_LivingObjects;
    }
  #endif
  };
  //------------------------------------------------------------------------------
  // ref
  //------------------------------------------------------------------------------
  /**
   * The ref<> class is used to reference-count an Object.
   * When the last ref<> that points to an Object is deallocated also the pointed Object is deallocated.
  */
  template<class T>
  class ref
  {
  public:
    ref(T* object=NULL)
    {
      mObject = object;
      if (mObject)
        mObject->incReference();
    }
    ref(const ref& other)
    {
      mObject = NULL;
      *this = other;
    }
    template<class T2> ref(const ref<T2>& other)
    {
      mObject = NULL;
      *this = other;
    }
    ~ref()
    {
      if (mObject)
        mObject->decReference();
      mObject = NULL;
    }
    ref& operator=(const ref& other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other.get();
      return *this;
    }
    template<class T2> ref& operator=(const ref<T2>& other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other.get();
      return *this;
    }
    ref& operator=(T* other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other;
      return *this;
    }
    template<class T2> ref& operator=(T2* other)
    {
      if (other)
        other->incReference();
      if (mObject)
        mObject->decReference();
      mObject = other;
      return *this;
    }
    void swap(ref& other)
    {
      T* tmp = other.get();
      other = mObject;
      mObject = tmp;
    }
    T* get() const { return mObject; }
    T* operator->() const { VL_CHECK(mObject); return mObject; }
    T& operator*() const { VL_CHECK(mObject); return *mObject; }
    bool operator<(const ref& other) const { return mObject < other.get(); }
    operator bool() const { return mObject != NULL; }

  protected:
    T* mObject;
  };
  // interaction with the other types
  template<class T1, class T2> inline bool operator==(const ref<T1> & o1, const ref<T2> & o2) { return o1.get() == o2.get(); }
  template<class T1, class T2> inline bool operator!=(const ref<T1> & o1, const ref<T2> & o2) { return o1.get() != o2.get(); }
  template<class T1, class T2> inline bool operator==(const ref<T1> & o1, T2 * o2) { return o1.get() == o2; }
  template<class T1, class T2> inline bool operator!=(const ref<T1> & o1, T2 * o2) { return o1.get() != o2; }
  template<class T1, class T2> inline bool operator==(T1 * o1, const ref<T2> & o2) { return o1 == o2.get(); }
  template<class T1, class T2> inline bool operator!=(T1 * o1, const ref<T2> & o2) { return o1 != o2.get(); }
}

#endif
<|endoftext|>


<commit_before>// Fill out your copyright notice in the Description page of Project Settings.

#include "BlockGenerator.h"
#include "Engine/World.h"
#include <EngineGlobals.h>
#include "Engine.h"
#include "Runtime/Engine/Public/HighResScreenshot.h"
#include "Runtime/Engine/Public/ImageUtils.h"
#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
#include <iostream>
#include <vector>
#include <array>
#include <fstream>
#include "Block.h"

//int viewStats = 0;

// Sets default values
ABlockGenerator::ABlockGenerator()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	static ConstructorHelpers::FObjectFinder<UStaticMesh> FoundMesh(TEXT("/Engine/EditorMeshes/EditorCube.EditorCube"));
	static ConstructorHelpers::FObjectFinder<UMaterial> FoundMaterial(TEXT("/Game/UnrealPianofall/Materials/M_Advanced_Block"));

	Block_Mesh = FoundMesh.Object;
	Block_Material = FoundMaterial.Object;

	std::array<uint32, 128> testArray = {};
	testArray[77] = 777;
	spawnpos.push_back(testArray); //Copy testArray into spawnpos

	FrameNr = 0;

	for (int i = 0; i < 22; ++i) { //green up
		rainbow[i] = { 255.0f, i*0.04545454545f, 0.0f };
	}
	for (int i = 22; i < 43; ++i) { //red down
		rainbow[i] = { 1.0f - ((i - 22)*0.04761904761f), 255.0f, 0.0f };
	}
	for (int i = 43; i < 64; ++i) { //blue up
		rainbow[i] = { 0.0f, 1.0f, (i - 43)*0.04761904761f };
	}
	for (int i = 64; i < 85; ++i) { //green down
		rainbow[i] = { 0.0f, 1.0f - ((i - 64)*0.04761904761f), 255.0f };
	}
	for (int i = 85; i < 106; ++i) { //reed up
		rainbow[i] = { (i - 85)*0.04761904761f, 0.0f, 255.0f };
	}
	for (int i = 106; i < 128; ++i) { //blue down
		rainbow[i] = { 255.0f, 0.0f, 1.0f - ((i - 106)*0.04545454545f) };
	}

}

// Called when the game starts or when spawned
void ABlockGenerator::BeginPlay()
{
	Super::BeginPlay();

	std::ifstream midifile("A:\\Music\\britney_spears-born_to_make_you_happy.mid", std::ios::binary);

	char header[14];
	midifile.read(header, 14);
	if (header[0] == 'M' &&
		header[1] == 'T' &&
		header[2] == 'h' &&
		header[3] == 'd' &&
		header[4] == 0 &&
		header[5] == 0 &&
		header[6] == 0 &&
		header[7] == 6) {
		UE_LOG(LogTemp, Log, TEXT("Valid MIDI-file!"));
		uint16 PPQ = (header[12] << 8) | header[13];
		if (PPQ == 0) {
			PPQ = 120;
		}
		UE_LOG(LogTemp, Log, TEXT("PPQ: %u"), PPQ);
		uint32 usPQ = 500000; //120 PBM
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("MIDI-File: Invalid header"));
		UE_LOG(LogTemp, Error, TEXT("Invalid MIDI-file!"));
	}

	bool in_MTrk = false;
	char MTrk[4] = {'M','T','r','k'};
	uint8 MTrk_findpos = 0;
	uint16 MTrk_readpos = 0;
	int32 MTrk_nr = -1;
	char buf[4096];
	do {
		UE_LOG(LogTemp, Log, TEXT("Read Block"));
		midifile.read(buf, 4096);

		MTrk_readpos = 0;
		if (in_MTrk == false) {
			for (uint16 i = 0; i < 4096; ++i) {
				if (buf[i] == MTrk[MTrk_findpos]) {
					UE_LOG(LogTemp, Log, TEXT("MTrk_findpos: %u"), MTrk_findpos + 1);
					if (++MTrk_findpos == 4) {
						UE_LOG(LogTemp, Log, TEXT("Found!"));
						MTrk_findpos = 0;
						++MTrk_nr;
						MTrk_readpos = i;
						in_MTrk = true;
						break;
					}
				} else {
					if (buf[i] == MTrk[0]) {
						MTrk_findpos = 1;
					} else {
						MTrk_findpos = 0;
					}
				}
			}
		}

		if (in_MTrk == true) {
			for (uint16 i = MTrk_readpos; i < 4096; ++i) {
				//UE_LOG(LogTemp, Log, TEXT("Hello World!"));
			}
		}
	} while (midifile);

}

// Called every frame
void ABlockGenerator::Tick(float DeltaTime)
{
	//UE_LOG(LogTemp, Log, TEXT("spawnpos[0][77]: %u"), spawnpos[0][77]);
	Super::Tick(DeltaTime);
	++FrameNr;

	int32 notenr_rnd;

	//for (int i = 0; i < 100; ++i) {
	notenr_rnd = (uint8)FMath::RandRange(0.0f, 127.0f);
	FVector location = FVector((float)(6400 - notenr_rnd * 100), 0.0f, 4000.0f);
	FRotator rotate = FRotator(0.0f, 0.0f, 0.0f);
	FActorSpawnParameters SpawnInfo;
	SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	SpawnInfo.Owner = this;
	SpawnInfo.Name = *FString::Printf(TEXT("F%uN%u"), FrameNr, notenr_rnd);
	AActor* newBlock = GetWorld()->SpawnActor<ABlock>(ABlock::StaticClass(), location, rotate, SpawnInfo);
	//}

	//++viewStats;
	//if (viewStats == 10) {
	//viewStats = 0;
	TArray<AActor*> FoundActors;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ABlock::StaticClass(), FoundActors);
	GEngine->AddOnScreenDebugMessage(1, 1.0f, FColor::Green, "FPS: " + FString::SanitizeFloat(1.0f / DeltaTime) + "\n" + "Blocks: " + FString::FromInt(FoundActors.Num()));
	//}

	//GetHighResScreenshotConfig().ResolutionMultiplier = 4; //Sets the res multiplier
	//GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot(); //Sets the flag in the viewport to take the high-res shot.

}

<commit_msg>Continued with the MIDI implementation<commit_after>// Fill out your copyright notice in the Description page of Project Settings.

#include "BlockGenerator.h"
#include "Engine/World.h"
#include <EngineGlobals.h>
#include "Engine.h"
#include "Runtime/Engine/Public/HighResScreenshot.h"
#include "Runtime/Engine/Public/ImageUtils.h"
#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
#include <fstream>
#include "Block.h"

//int viewStats = 0;

// Sets default values
ABlockGenerator::ABlockGenerator()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	static ConstructorHelpers::FObjectFinder<UStaticMesh> FoundMesh(TEXT("/Engine/EditorMeshes/EditorCube.EditorCube"));
	static ConstructorHelpers::FObjectFinder<UMaterial> FoundMaterial(TEXT("/Game/UnrealPianofall/Materials/M_Advanced_Block"));

	Block_Mesh = FoundMesh.Object;
	Block_Material = FoundMaterial.Object;

	std::array<uint32, 128> testArray = {};
	testArray[77] = 777;
	spawnpos.push_back(testArray); //Copy testArray into spawnpos

	FrameNr = 0;

	for (int i = 0; i < 22; ++i) { //green up
		rainbow[i] = { 255.0f, i*0.04545454545f, 0.0f };
	}
	for (int i = 22; i < 43; ++i) { //red down
		rainbow[i] = { 1.0f - ((i - 22)*0.04761904761f), 255.0f, 0.0f };
	}
	for (int i = 43; i < 64; ++i) { //blue up
		rainbow[i] = { 0.0f, 1.0f, (i - 43)*0.04761904761f };
	}
	for (int i = 64; i < 85; ++i) { //green down
		rainbow[i] = { 0.0f, 1.0f - ((i - 64)*0.04761904761f), 255.0f };
	}
	for (int i = 85; i < 106; ++i) { //reed up
		rainbow[i] = { (i - 85)*0.04761904761f, 0.0f, 255.0f };
	}
	for (int i = 106; i < 128; ++i) { //blue down
		rainbow[i] = { 255.0f, 0.0f, 1.0f - ((i - 106)*0.04545454545f) };
	}

}

// Called when the game starts or when spawned
void ABlockGenerator::BeginPlay()
{
	Super::BeginPlay();

	//std::ifstream midifile("A:\\Music\\britney_spears-born_to_make_you_happy.mid", std::ios::binary);
	std::ifstream midifile("A:\\Music\\05ClassExample60bpm.mid", std::ios::binary);

	uint16 PPQ;
	uint32 usPQ = 500000; //120 PBM
	uint64 time = 0;

	uint8 Length_len = 0;
	uint32 MTrk_len = 0;

	bool in_deltatime;
	int16 Controller_to_change = -1;
	int16 Controller_type = -1;
	uint8 Controller_data;
	uint8 deltatime_size = 0;
	uint8 deltatime_data[5] = {};

	int8 Patch_to_change = -1;
	int8 PatchTable[16] = { 0 };

	bool in_META = false;
	int16 META_type = -1;
	int16 META_len = -1;
	uint8 MIDI_data_size = 0;
	uint8 MIDI_data_pos = 0;
	uint8 META_data[255] = {};

	char MTrk[4] = { 'M','T','r','k' };
	uint8 MTrk_findpos = 0;
	uint16 pos = 0;
	std::stringstream ss;
	int32 MTrk_nr = -1;
	char filebuf[4096] = { 0 };

	char hexstr[100];

	char header[14];
	midifile.read(header, 14);
	if (header[0] == 'M' &&
		header[1] == 'T' &&
		header[2] == 'h' &&
		header[3] == 'd' &&
		header[4] == 0 &&
		header[5] == 0 &&
		header[6] == 0 &&
		header[7] == 6) {
		UE_LOG(LogTemp, Log, TEXT("Valid MIDI-file!"));
		PPQ = (header[12] << 8) + header[13];
		if (PPQ == 0) {
			PPQ = 120;
		}
		UE_LOG(LogTemp, Log, TEXT("PPQ: %u"), PPQ);
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("MIDI-File: Invalid header"));
		UE_LOG(LogTemp, Error, TEXT("Invalid MIDI-file!"));
	}

	do {
		UE_LOG(LogTemp, Log, TEXT("Read Block"));
		midifile.read(filebuf, 4096);
		unsigned char *buf = (unsigned char *)filebuf;
		pos = 0;

		read_next_MTrk:

		if (MTrk_len == 0) {
			for (; pos < 4096; ++pos) {
				if (buf[pos] == MTrk[MTrk_findpos]) {
					if (++MTrk_findpos == 4) {
						UE_LOG(LogTemp, Log, TEXT("MTrk Found!"));
						usPQ = 500000; //120 PBM
						time = 0;
						MTrk_findpos = 0;
						++MTrk_nr;
						MTrk_len = 0;
						Length_len = 4;
						deltatime_size = 0;
						Controller_to_change = -1;
						Controller_type = -1;
						Patch_to_change = -1;
						in_META = false;
						META_type = -1;
						META_len = -1;
						++pos;
						break;
					}
				} else {
					if (buf[pos] == MTrk[0]) {
						MTrk_findpos = 1;
					} else {
						MTrk_findpos = 0;
					}
				}
			}
		}

		UE_LOG(LogTemp, Log, TEXT("pos: %u"), pos);

		if (Length_len > 0) {
			for (; pos < 4096; ++pos) {
				_itoa((uint8)buf[pos], hexstr, 16);
				UE_LOG(LogTemp, Log, TEXT("Length Data: %s"), ANSI_TO_TCHAR(hexstr));
				MTrk_len += buf[pos] << (--Length_len * 8);
				if (Length_len == 0) {
					UE_LOG(LogTemp, Log, TEXT("MTrk_len: %u"), MTrk_len);
					++pos;
					in_deltatime = true;
					break;
				}
			}

		}

		if (MTrk_len > 0) {
			for (; pos < 4096; ++pos) {
				_itoa((uint8)buf[pos], hexstr, 16);
				UE_LOG(LogTemp, Log, TEXT("MTrk_len: %u Data: %s = %d"), MTrk_len, ANSI_TO_TCHAR(hexstr), buf[pos]);
				if (--MTrk_len == 0) {
					UE_LOG(LogTemp, Log, TEXT("META-End!"));
					if (in_META == false || META_type != 0x2F) {
						UE_LOG(LogTemp, Warning, TEXT("Invalid end-of-track MIDI-event!"));
					}
					in_META = false;
					goto read_next_MTrk;
				}

				if (in_deltatime == true) {
					deltatime_data[deltatime_size++] = buf[pos] & 0b01111111;
					if (buf[pos] < 0b10000000) {
						deltatime_size = 0;
						in_deltatime = false;
					}
					continue;
				}

				if (buf[pos] >= 0b10000000) {
					if (buf[pos] >= 0xB0 && buf[pos] <= 0xBF) {
						UE_LOG(LogTemp, Log, TEXT("ControllerChange: Channel %u"), buf[pos] - 0xB0);
						Controller_to_change = buf[pos] - 0xB0;
					}
					else if (buf[pos] >= 0xC0 && buf[pos] <= 0xCF) {
						UE_LOG(LogTemp, Log, TEXT("PatchChange: Channel %u"), buf[pos] - 0xC0);
						Patch_to_change = buf[pos] - 0xC0;
					}
					else if (buf[pos] == 0xFF) {
						UE_LOG(LogTemp, Log, TEXT("META-Start"));
						MIDI_data_pos = 0;
						META_len = -1;
						META_type = -1;
						in_META = true;
					}
					else {
						UE_LOG(LogTemp, Log, TEXT("Error: Unknown MIDI Event %u"), buf[pos]);
					}
				}

				else {

					if (Controller_to_change != -1) {
						if (Controller_type == -1) {
							Controller_type = buf[pos];
						}
						else {
							Controller_data = buf[pos];
							Controller_type = -1;
							Controller_to_change = -1;
							in_deltatime = true;
						}
					}

					else if (Patch_to_change != -1) {
						UE_LOG(LogTemp, Log, TEXT("PatchChange: Channel %d = %u"), Patch_to_change, buf[pos]);
						PatchTable[Patch_to_change] = buf[pos];
						Patch_to_change = -1;
						in_deltatime = true;
					}

					else if (in_META == true) {
						if (META_type == -1) {
							UE_LOG(LogTemp, Log, TEXT("META_type = %u"), buf[pos]);
							META_type = buf[pos];
						}
						else {
							if (META_len == -1) {
								UE_LOG(LogTemp, Log, TEXT("META_len = %u"), buf[pos]);
								META_len = buf[pos];
								MIDI_data_size = buf[pos];
							}
							else {
								--META_len;
								META_data[MIDI_data_pos++] = buf[pos];
								if (META_len == 0) {
									--MIDI_data_pos;
									if (META_type == 0x51) {
										usPQ = 0;
										for (uint16 MIDI_data_i = 0; MIDI_data_i < MIDI_data_size; ++MIDI_data_i) {
											usPQ += META_data[MIDI_data_i] << ((MIDI_data_size - MIDI_data_i - 1) * 8);
										}
										if (usPQ == 0) {
											usPQ = 500000; //120 PBM
										}
										UE_LOG(LogTemp, Log, TEXT("New usPQ = %u"), usPQ);
									}
									UE_LOG(LogTemp, Log, TEXT("META-End!"));
									in_META = false;
									in_deltatime = true;
								}
							}
						}
					}
				}
			}
		}

	} while (midifile);

}

// Called every frame
void ABlockGenerator::Tick(float DeltaTime)
{
	//UE_LOG(LogTemp, Log, TEXT("spawnpos[0][77]: %u"), spawnpos[0][77]);
	Super::Tick(DeltaTime);
	++FrameNr;

	int32 notenr_rnd;

	for (int i = 0; i < 100; ++i) {
		notenr_rnd = (uint8)FMath::RandRange(0.0f, 127.0f);
		FVector location = FVector((float)(6400 - notenr_rnd * 100), 0.0f, 4000.0f);
		FRotator rotate = FRotator(0.0f, 0.0f, 0.0f);
		FActorSpawnParameters SpawnInfo;
		SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
		SpawnInfo.Owner = this;
		SpawnInfo.Name = *FString::Printf(TEXT("F%uN%u"), FrameNr, notenr_rnd);
		AActor* newBlock = GetWorld()->SpawnActor<ABlock>(ABlock::StaticClass(), location, rotate, SpawnInfo);
	}

	//++viewStats;
	//if (viewStats == 10) {
	//viewStats = 0;
	TArray<AActor*> FoundActors;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ABlock::StaticClass(), FoundActors);
	GEngine->AddOnScreenDebugMessage(1, 1.0f, FColor::Green, "FPS: " + FString::SanitizeFloat(1.0f / DeltaTime) + "\n" + "Blocks: " + FString::FromInt(FoundActors.Num()));
	//}

	//GetHighResScreenshotConfig().ResolutionMultiplier = 4; //Sets the res multiplier
	//GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot(); //Sets the flag in the viewport to take the high-res shot.

}

<|endoftext|>