<commit_before>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#include <map>
#include <boost/mpi.hpp>
#include <iostream>

#include "global.hpp"
#include "conflict.hpp"
#include "config.hpp"
#include "bind.hpp"
#include "mem.hpp"
#ifdef USE_GPU
#include "gpu_mem.hpp"
#endif
#include "string_server.hpp"
#include "dgraph.hpp"
#include "proxy.hpp"
#include "console.hpp"
#include "rdma.hpp"
#include "data_statistic.hpp"
#include "logger2.hpp"

#include "engine/engine.hpp"
#include "comm/adaptor.hpp"

#include "unit.hpp"

void *engine_thread(void *arg)
{
    Engine *engine = (Engine *)arg;
    if (enable_binding && core_bindings.count(engine->tid) != 0)
        bind_to_core(core_bindings[engine->tid]);
    else
        bind_to_core(default_bindings[engine->tid % num_cores]);

    engine->run();
}

void *proxy_thread(void *arg)
{
    Proxy *proxy = (Proxy *)arg;
    if (enable_binding && core_bindings.count(proxy->tid) != 0)
        bind_to_core(core_bindings[proxy->tid]);
    else
        bind_to_core(default_bindings[proxy->tid % num_cores]);

    // run the builtin console
    run_console(proxy);
}

static void
usage(char *fn)
{
    cout << "usage: " << fn << " <config_fname> <host_fname> [options]" << endl;
    cout << "options:" << endl;
    cout << "  -b binding : the file of core binding" << endl;
    cout << "  -c command : the one-shot command" << endl;
}

int
main(int argc, char *argv[])
{
    conflict_detector();

    boost::mpi::environment env(argc, argv);
    boost::mpi::communicator world;
    int sid = world.rank(); // server ID

    if (argc < 3) {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

    // load global configs
    load_config(string(argv[1]), world.size());

    // set the address file of host/cluster
    string host_fname = std::string(argv[2]);

    // load CPU topology by hwloc
    load_node_topo();
    logstream(LOG_INFO) << "#" << sid << ": has " << num_cores << " cores." << LOG_endl;

    int c;
    while ((c = getopt(argc - 2, argv + 2, "b:c:")) != -1) {
        switch (c) {
        case 'b':
            enable_binding = load_core_binding(optarg);
            break;
        case 'c':
            enable_oneshot = true;
            oneshot_cmd = optarg;
            break;
        default:
            usage(argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // allocate memory regions
    vector<RDMA::MemoryRegion> mrs;

    // rdma broadcast memory
    vector<Broadcast_Mem *> bc_mems;
    Broadcast_Mem *mb_mem = new Broadcast_Mem(global_num_servers, global_num_threads);
    bc_mems.push_back(mb_mem);
    // CPU (host) memory
    Mem *mem = new Mem(global_num_servers, global_num_threads, bc_mems);
    logstream(LOG_INFO) << "#" << sid << ": allocate " << B2GiB(mem->size()) << "GB memory" << LOG_endl;
    RDMA::MemoryRegion mr_cpu = { RDMA::MemType::CPU, mem->address(), mem->size(), mem };
    mrs.push_back(mr_cpu);

#ifdef USE_GPU
    // GPU (device) memory
    int devid = 0; // FIXME: it means one GPU device?
    GPUMem *gpu_mem = new GPUMem(devid, global_num_servers, global_num_gpus);
    logstream(LOG_INFO) << "#" << sid << ": allocate " << B2GiB(gpu_mem->size()) << "GB GPU memory" << LOG_endl;
    RDMA::MemoryRegion mr_gpu = { RDMA::MemType::GPU, gpu_mem->address(), gpu_mem->size(), gpu_mem };
    mrs.push_back(mr_gpu);
#endif

    // two additional threads,
    // one for broadcast master, another for broadcast slave
    int rdma_init_nthreads = global_num_threads + 2;
    // init RDMA devices and connections
    RDMA_init(global_num_servers, rdma_init_nthreads, sid, mrs, host_fname);

    // init communication
    RDMA_Adaptor *rdma_adaptor = new RDMA_Adaptor(sid, mrs,
            global_num_servers, global_num_threads);
    TCP_Adaptor *tcp_adaptor = new TCP_Adaptor(sid, host_fname, global_data_port_base,
            global_num_servers, global_num_threads);

    // init control communicaiton
    con_adaptor = new TCP_Adaptor(sid, host_fname, global_ctrl_port_base,
                                  global_num_servers, global_num_proxies);

    // load string server (read-only, shared by all proxies and all engines)
    String_Server str_server(global_input_folder);

    // load RDF graph (shared by all engines and proxies)
    DGraph dgraph(sid, mem, &str_server, global_input_folder);

    // prepare statistics for SPARQL optimizer
    data_statistic stat(sid);
    if (global_generate_statistics) {
        uint64_t t0 = timer::get_usec();
        dgraph.generate_statistic(stat);
        uint64_t t1 = timer::get_usec();
        logstream(LOG_EMPH)  << "generate_statistic using time: " << t1 - t0 << "usec" << LOG_endl;
        stat.gather_stat(con_adaptor);
    } else {
        // use the dataset name by default
        string fname = global_input_folder + "/statfile";
        stat.load_stat_from_file(fname, con_adaptor);
    }

    // create proxies and engines
    ASSERT(global_num_threads == global_num_proxies + global_num_engines);
    for (int tid = 0; tid < global_num_threads; tid++) {
        Adaptor *adaptor = new Adaptor(tid, tcp_adaptor, rdma_adaptor);

        // TID: proxy = [0, #proxies), engine = [#proxies, #proxies + #engines)
        if (tid < global_num_proxies) {
            Proxy *proxy = new Proxy(sid, tid, &str_server, &dgraph, adaptor, &stat);
            proxies.push_back(proxy);
        } else {
            Engine *engine = new Engine(sid, tid, &str_server, &dgraph, adaptor);
            engines.push_back(engine);
        }
    }

    // launch all proxies and engines
    pthread_t *threads  = new pthread_t[global_num_threads];
    for (int tid = 0; tid < global_num_threads; tid++) {
        // TID: proxy = [0, #proxies), engine = [#proxies, #proxies + #engines)
        if (tid < global_num_proxies)
            pthread_create(&(threads[tid]), NULL, proxy_thread, (void *)proxies[tid]);
        else
            pthread_create(&(threads[tid]), NULL, engine_thread, (void *)engines[tid - global_num_proxies]);
    }

    // wait to all threads termination
    for (size_t t = 0; t < global_num_threads; t++) {
        if (int rc = pthread_join(threads[t], NULL)) {
            logger(LOG_ERROR, "return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
    }

    /// TODO: exit gracefully (properly call MPI_Init() and MPI_Finalize(), delete all objects)
    return 0;
}
<commit_msg>name refine<commit_after>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#include <map>
#include <boost/mpi.hpp>
#include <iostream>

#include "global.hpp"
#include "conflict.hpp"
#include "config.hpp"
#include "bind.hpp"
#include "mem.hpp"
#ifdef USE_GPU
#include "gpu_mem.hpp"
#endif
#include "string_server.hpp"
#include "dgraph.hpp"
#include "proxy.hpp"
#include "console.hpp"
#include "rdma.hpp"
#include "data_statistic.hpp"
#include "logger2.hpp"

#include "engine/engine.hpp"
#include "comm/adaptor.hpp"

#include "unit.hpp"

void *engine_thread(void *arg)
{
    Engine *engine = (Engine *)arg;
    if (enable_binding && core_bindings.count(engine->tid) != 0)
        bind_to_core(core_bindings[engine->tid]);
    else
        bind_to_core(default_bindings[engine->tid % num_cores]);

    engine->run();
}

void *proxy_thread(void *arg)
{
    Proxy *proxy = (Proxy *)arg;
    if (enable_binding && core_bindings.count(proxy->tid) != 0)
        bind_to_core(core_bindings[proxy->tid]);
    else
        bind_to_core(default_bindings[proxy->tid % num_cores]);

    // run the builtin console
    run_console(proxy);
}

static void
usage(char *fn)
{
    cout << "usage: " << fn << " <config_fname> <host_fname> [options]" << endl;
    cout << "options:" << endl;
    cout << "  -b binding : the file of core binding" << endl;
    cout << "  -c command : the one-shot command" << endl;
}

int
main(int argc, char *argv[])
{
    conflict_detector();

    boost::mpi::environment env(argc, argv);
    boost::mpi::communicator world;
    int sid = world.rank(); // server ID

    if (argc < 3) {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

    // load global configs
    load_config(string(argv[1]), world.size());

    // set the address file of host/cluster
    string host_fname = std::string(argv[2]);

    // load CPU topology by hwloc
    load_node_topo();
    logstream(LOG_INFO) << "#" << sid << ": has " << num_cores << " cores." << LOG_endl;

    int c;
    while ((c = getopt(argc - 2, argv + 2, "b:c:")) != -1) {
        switch (c) {
        case 'b':
            enable_binding = load_core_binding(optarg);
            break;
        case 'c':
            enable_oneshot = true;
            oneshot_cmd = optarg;
            break;
        default:
            usage(argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // allocate memory regions
    vector<RDMA::MemoryRegion> mrs;

    // rdma broadcast memory
    vector<Broadcast_Mem *> bcast_mems;
    Broadcast_Mem *ss_bcast_mem = new Broadcast_Mem(global_num_servers, global_num_threads);
    bcast_mems.push_back(ss_bcast_mem);
    // CPU (host) memory
    Mem *mem = new Mem(global_num_servers, global_num_threads, bcast_mems);
    logstream(LOG_INFO) << "#" << sid << ": allocate " << B2GiB(mem->size()) << "GB memory" << LOG_endl;
    RDMA::MemoryRegion mr_cpu = { RDMA::MemType::CPU, mem->address(), mem->size(), mem };
    mrs.push_back(mr_cpu);

#ifdef USE_GPU
    // GPU (device) memory
    int devid = 0; // FIXME: it means one GPU device?
    GPUMem *gpu_mem = new GPUMem(devid, global_num_servers, global_num_gpus);
    logstream(LOG_INFO) << "#" << sid << ": allocate " << B2GiB(gpu_mem->size()) << "GB GPU memory" << LOG_endl;
    RDMA::MemoryRegion mr_gpu = { RDMA::MemType::GPU, gpu_mem->address(), gpu_mem->size(), gpu_mem };
    mrs.push_back(mr_gpu);
#endif

    // RDMA full-link communication
    int flink_nthreads = global_num_proxies + global_num_engines;
    // RDMA broadcast communication
    int bcast_nthreads = 2;
    int rdma_init_nthreads = flink_nthreads + bcast_nthreads;
    // init RDMA devices and connections
    RDMA_init(global_num_servers, rdma_init_nthreads, sid, mrs, host_fname);

    // init communication
    RDMA_Adaptor *rdma_adaptor = new RDMA_Adaptor(sid, mrs,
            global_num_servers, global_num_threads);
    TCP_Adaptor *tcp_adaptor = new TCP_Adaptor(sid, host_fname, global_data_port_base,
            global_num_servers, global_num_threads);

    // init control communicaiton
    con_adaptor = new TCP_Adaptor(sid, host_fname, global_ctrl_port_base,
                                  global_num_servers, global_num_proxies);

    // load string server (read-only, shared by all proxies and all engines)
    String_Server str_server(global_input_folder);

    // load RDF graph (shared by all engines and proxies)
    DGraph dgraph(sid, mem, &str_server, global_input_folder);

    // prepare statistics for SPARQL optimizer
    data_statistic stat(sid);
    if (global_generate_statistics) {
        uint64_t t0 = timer::get_usec();
        dgraph.generate_statistic(stat);
        uint64_t t1 = timer::get_usec();
        logstream(LOG_EMPH)  << "generate_statistic using time: " << t1 - t0 << "usec" << LOG_endl;
        stat.gather_stat(con_adaptor);
    } else {
        // use the dataset name by default
        string fname = global_input_folder + "/statfile";
        stat.load_stat_from_file(fname, con_adaptor);
    }

    // create proxies and engines
    ASSERT(global_num_threads == global_num_proxies + global_num_engines);
    for (int tid = 0; tid < global_num_threads; tid++) {
        Adaptor *adaptor = new Adaptor(tid, tcp_adaptor, rdma_adaptor);

        // TID: proxy = [0, #proxies), engine = [#proxies, #proxies + #engines)
        if (tid < global_num_proxies) {
            Proxy *proxy = new Proxy(sid, tid, &str_server, &dgraph, adaptor, &stat);
            proxies.push_back(proxy);
        } else {
            Engine *engine = new Engine(sid, tid, &str_server, &dgraph, adaptor);
            engines.push_back(engine);
        }
    }

    // launch all proxies and engines
    pthread_t *threads  = new pthread_t[global_num_threads];
    for (int tid = 0; tid < global_num_threads; tid++) {
        // TID: proxy = [0, #proxies), engine = [#proxies, #proxies + #engines)
        if (tid < global_num_proxies)
            pthread_create(&(threads[tid]), NULL, proxy_thread, (void *)proxies[tid]);
        else
            pthread_create(&(threads[tid]), NULL, engine_thread, (void *)engines[tid - global_num_proxies]);
    }

    // wait to all threads termination
    for (size_t t = 0; t < global_num_threads; t++) {
        if (int rc = pthread_join(threads[t], NULL)) {
            logger(LOG_ERROR, "return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
    }

    /// TODO: exit gracefully (properly call MPI_Init() and MPI_Finalize(), delete all objects)
    return 0;
}
<|endoftext|>


<commit_before>//===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Target/UnixSignals.h"
#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/LinuxSignals.h"
#include "Plugins/Process/Utility/MipsLinuxSignals.h"
#include "Plugins/Process/Utility/NetBSDSignals.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Utility/ArchSpec.h"

using namespace lldb_private;

UnixSignals::Signal::Signal(const char *name, bool default_suppress,
                            bool default_stop, bool default_notify,
                            const char *description, const char *alias)
    : m_name(name), m_alias(alias), m_description(),
      m_suppress(default_suppress), m_stop(default_stop),
      m_notify(default_notify) {
  if (description)
    m_description.assign(description);
}

lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
  const auto &triple = arch.GetTriple();
  switch (triple.getOS()) {
  case llvm::Triple::Linux: {
    switch (triple.getArch()) {
    case llvm::Triple::mips:
    case llvm::Triple::mipsel:
    case llvm::Triple::mips64:
    case llvm::Triple::mips64el:
      return std::make_shared<MipsLinuxSignals>();
    default:
      return std::make_shared<LinuxSignals>();
    }
  }
  case llvm::Triple::FreeBSD:
  case llvm::Triple::OpenBSD:
    return std::make_shared<FreeBSDSignals>();
  case llvm::Triple::NetBSD:
    return std::make_shared<NetBSDSignals>();
  default:
    return std::make_shared<UnixSignals>();
  }
}

//----------------------------------------------------------------------
// UnixSignals constructor
//----------------------------------------------------------------------
UnixSignals::UnixSignals() { Reset(); }

UnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {}

UnixSignals::~UnixSignals() = default;

void UnixSignals::Reset() {
  // This builds one standard set of Unix Signals.  If yours aren't quite in
  // this order, you can either subclass this class, and use Add & Remove to
  // change them
  // or you can subclass and build them afresh in your constructor;
  //
  // Note: the signals below are the Darwin signals.  Do not change these!
  m_signals.clear();
  //        SIGNO  NAME          SUPPRESS STOP   NOTIFY DESCRIPTION
  //        ====== ============  ======== ====== ======
  //        ===================================================
  AddSignal(1, "SIGHUP", false, true, true, "hangup");
  AddSignal(2, "SIGINT", true, true, true, "interrupt");
  AddSignal(3, "SIGQUIT", false, true, true, "quit");
  AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
  AddSignal(5, "SIGTRAP", true, true, true,
            "trace trap (not reset when caught)");
  AddSignal(6, "SIGABRT", false, true, true, "abort()");
  AddSignal(7, "SIGEMT", false, true, true, "pollable event");
  AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
  AddSignal(9, "SIGKILL", false, true, true, "kill");
  AddSignal(10, "SIGBUS", false, true, true, "bus error");
  AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
  AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call");
  AddSignal(13, "SIGPIPE", false, true, true,
            "write on a pipe with no one to read it");
  AddSignal(14, "SIGALRM", false, false, false, "alarm clock");
  AddSignal(15, "SIGTERM", false, true, true,
            "software termination signal from kill");
  AddSignal(16, "SIGURG", false, false, false,
            "urgent condition on IO channel");
  AddSignal(17, "SIGSTOP", true, true, true,
            "sendable stop signal not from tty");
  AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty");
  AddSignal(19, "SIGCONT", false, true, true, "continue a stopped process");
  AddSignal(20, "SIGCHLD", false, false, false,
            "to parent on child stop or exit");
  AddSignal(21, "SIGTTIN", false, true, true,
            "to readers process group upon background tty read");
  AddSignal(22, "SIGTTOU", false, true, true,
            "to readers process group upon background tty write");
  AddSignal(23, "SIGIO", false, false, false, "input/output possible signal");
  AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit");
  AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit");
  AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm");
  AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
  AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
  AddSignal(29, "SIGINFO", false, true, true, "information request");
  AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
  AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
}

void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
                            bool default_stop, bool default_notify,
                            const char *description, const char *alias) {
  Signal new_signal(name, default_suppress, default_stop, default_notify,
                    description, alias);
  m_signals.insert(std::make_pair(signo, new_signal));
  ++m_version;
}

void UnixSignals::RemoveSignal(int signo) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    m_signals.erase(pos);
  ++m_version;
}

const char *UnixSignals::GetSignalAsCString(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos == m_signals.end())
    return nullptr;
  else
    return pos->second.m_name.GetCString();
}

bool UnixSignals::SignalIsValid(int32_t signo) const {
  return m_signals.find(signo) != m_signals.end();
}

ConstString UnixSignals::GetShortName(ConstString name) const {
  if (name) {
    const char *signame = name.AsCString();
    return ConstString(signame + 3); // Remove "SIG" from name
  }
  return name;
}

int32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
  ConstString const_name(name);

  collection::const_iterator pos, end = m_signals.end();
  for (pos = m_signals.begin(); pos != end; pos++) {
    if ((const_name == pos->second.m_name) ||
        (const_name == pos->second.m_alias) ||
        (const_name == GetShortName(pos->second.m_name)) ||
        (const_name == GetShortName(pos->second.m_alias)))
      return pos->first;
  }

  const int32_t signo =
      StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return signo;
  return LLDB_INVALID_SIGNAL_NUMBER;
}

int32_t UnixSignals::GetFirstSignalNumber() const {
  if (m_signals.empty())
    return LLDB_INVALID_SIGNAL_NUMBER;

  return (*m_signals.begin()).first;
}

int32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const {
  collection::const_iterator pos = m_signals.find(current_signal);
  collection::const_iterator end = m_signals.end();
  if (pos == end)
    return LLDB_INVALID_SIGNAL_NUMBER;
  else {
    pos++;
    if (pos == end)
      return LLDB_INVALID_SIGNAL_NUMBER;
    else
      return pos->first;
  }
}

const char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress,
                                       bool &should_stop,
                                       bool &should_notify) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos == m_signals.end())
    return nullptr;
  else {
    const Signal &signal = pos->second;
    should_suppress = signal.m_suppress;
    should_stop = signal.m_stop;
    should_notify = signal.m_notify;
    return signal.m_name.AsCString("");
  }
}

bool UnixSignals::GetShouldSuppress(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_suppress;
  return false;
}

bool UnixSignals::SetShouldSuppress(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_suppress = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldSuppress(signo, value);
  return false;
}

bool UnixSignals::GetShouldStop(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_stop;
  return false;
}

bool UnixSignals::SetShouldStop(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_stop = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldStop(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldStop(signo, value);
  return false;
}

bool UnixSignals::GetShouldNotify(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_notify;
  return false;
}

bool UnixSignals::SetShouldNotify(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_notify = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldNotify(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldNotify(signo, value);
  return false;
}

int32_t UnixSignals::GetNumSignals() const { return m_signals.size(); }

int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
  if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
    return LLDB_INVALID_SIGNAL_NUMBER;
  auto it = m_signals.begin();
  std::advance(it, index);
  return it->first;
}

uint64_t UnixSignals::GetVersion() const { return m_version; }

std::vector<int32_t>
UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
                                llvm::Optional<bool> should_stop,
                                llvm::Optional<bool> should_notify) {
  std::vector<int32_t> result;
  for (int32_t signo = GetFirstSignalNumber();
       signo != LLDB_INVALID_SIGNAL_NUMBER;
       signo = GetNextSignalNumber(signo)) {

    bool signal_suppress = false;
    bool signal_stop = false;
    bool signal_notify = false;
    GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);

    // If any of filtering conditions are not met, we move on to the next
    // signal.
    if (should_suppress.hasValue() &&
        signal_suppress != should_suppress.getValue())
      continue;

    if (should_stop.hasValue() && signal_stop != should_stop.getValue())
      continue;

    if (should_notify.hasValue() && signal_notify != should_notify.getValue())
      continue;

    result.push_back(signo);
  }

  return result;
}
<commit_msg>Change the default handling for SIGPIPE to pass/,no-stop/no-notify.<commit_after>//===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Target/UnixSignals.h"
#include "Plugins/Process/Utility/FreeBSDSignals.h"
#include "Plugins/Process/Utility/LinuxSignals.h"
#include "Plugins/Process/Utility/MipsLinuxSignals.h"
#include "Plugins/Process/Utility/NetBSDSignals.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Utility/ArchSpec.h"

using namespace lldb_private;

UnixSignals::Signal::Signal(const char *name, bool default_suppress,
                            bool default_stop, bool default_notify,
                            const char *description, const char *alias)
    : m_name(name), m_alias(alias), m_description(),
      m_suppress(default_suppress), m_stop(default_stop),
      m_notify(default_notify) {
  if (description)
    m_description.assign(description);
}

lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
  const auto &triple = arch.GetTriple();
  switch (triple.getOS()) {
  case llvm::Triple::Linux: {
    switch (triple.getArch()) {
    case llvm::Triple::mips:
    case llvm::Triple::mipsel:
    case llvm::Triple::mips64:
    case llvm::Triple::mips64el:
      return std::make_shared<MipsLinuxSignals>();
    default:
      return std::make_shared<LinuxSignals>();
    }
  }
  case llvm::Triple::FreeBSD:
  case llvm::Triple::OpenBSD:
    return std::make_shared<FreeBSDSignals>();
  case llvm::Triple::NetBSD:
    return std::make_shared<NetBSDSignals>();
  default:
    return std::make_shared<UnixSignals>();
  }
}

//----------------------------------------------------------------------
// UnixSignals constructor
//----------------------------------------------------------------------
UnixSignals::UnixSignals() { Reset(); }

UnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {}

UnixSignals::~UnixSignals() = default;

void UnixSignals::Reset() {
  // This builds one standard set of Unix Signals.  If yours aren't quite in
  // this order, you can either subclass this class, and use Add & Remove to
  // change them
  // or you can subclass and build them afresh in your constructor;
  //
  // Note: the signals below are the Darwin signals.  Do not change these!
  m_signals.clear();
  //        SIGNO  NAME          SUPPRESS STOP   NOTIFY DESCRIPTION
  //        ====== ============  ======== ====== ======
  //        ===================================================
  AddSignal(1, "SIGHUP", false, true, true, "hangup");
  AddSignal(2, "SIGINT", true, true, true, "interrupt");
  AddSignal(3, "SIGQUIT", false, true, true, "quit");
  AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
  AddSignal(5, "SIGTRAP", true, true, true,
            "trace trap (not reset when caught)");
  AddSignal(6, "SIGABRT", false, true, true, "abort()");
  AddSignal(7, "SIGEMT", false, true, true, "pollable event");
  AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
  AddSignal(9, "SIGKILL", false, true, true, "kill");
  AddSignal(10, "SIGBUS", false, true, true, "bus error");
  AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
  AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call");
  AddSignal(13, "SIGPIPE", false, false, false,
            "write on a pipe with no one to read it");
  AddSignal(14, "SIGALRM", false, false, false, "alarm clock");
  AddSignal(15, "SIGTERM", false, true, true,
            "software termination signal from kill");
  AddSignal(16, "SIGURG", false, false, false,
            "urgent condition on IO channel");
  AddSignal(17, "SIGSTOP", true, true, true,
            "sendable stop signal not from tty");
  AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty");
  AddSignal(19, "SIGCONT", false, true, true, "continue a stopped process");
  AddSignal(20, "SIGCHLD", false, false, false,
            "to parent on child stop or exit");
  AddSignal(21, "SIGTTIN", false, true, true,
            "to readers process group upon background tty read");
  AddSignal(22, "SIGTTOU", false, true, true,
            "to readers process group upon background tty write");
  AddSignal(23, "SIGIO", false, false, false, "input/output possible signal");
  AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit");
  AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit");
  AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm");
  AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
  AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
  AddSignal(29, "SIGINFO", false, true, true, "information request");
  AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
  AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
}

void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
                            bool default_stop, bool default_notify,
                            const char *description, const char *alias) {
  Signal new_signal(name, default_suppress, default_stop, default_notify,
                    description, alias);
  m_signals.insert(std::make_pair(signo, new_signal));
  ++m_version;
}

void UnixSignals::RemoveSignal(int signo) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    m_signals.erase(pos);
  ++m_version;
}

const char *UnixSignals::GetSignalAsCString(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos == m_signals.end())
    return nullptr;
  else
    return pos->second.m_name.GetCString();
}

bool UnixSignals::SignalIsValid(int32_t signo) const {
  return m_signals.find(signo) != m_signals.end();
}

ConstString UnixSignals::GetShortName(ConstString name) const {
  if (name) {
    const char *signame = name.AsCString();
    return ConstString(signame + 3); // Remove "SIG" from name
  }
  return name;
}

int32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
  ConstString const_name(name);

  collection::const_iterator pos, end = m_signals.end();
  for (pos = m_signals.begin(); pos != end; pos++) {
    if ((const_name == pos->second.m_name) ||
        (const_name == pos->second.m_alias) ||
        (const_name == GetShortName(pos->second.m_name)) ||
        (const_name == GetShortName(pos->second.m_alias)))
      return pos->first;
  }

  const int32_t signo =
      StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return signo;
  return LLDB_INVALID_SIGNAL_NUMBER;
}

int32_t UnixSignals::GetFirstSignalNumber() const {
  if (m_signals.empty())
    return LLDB_INVALID_SIGNAL_NUMBER;

  return (*m_signals.begin()).first;
}

int32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const {
  collection::const_iterator pos = m_signals.find(current_signal);
  collection::const_iterator end = m_signals.end();
  if (pos == end)
    return LLDB_INVALID_SIGNAL_NUMBER;
  else {
    pos++;
    if (pos == end)
      return LLDB_INVALID_SIGNAL_NUMBER;
    else
      return pos->first;
  }
}

const char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress,
                                       bool &should_stop,
                                       bool &should_notify) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos == m_signals.end())
    return nullptr;
  else {
    const Signal &signal = pos->second;
    should_suppress = signal.m_suppress;
    should_stop = signal.m_stop;
    should_notify = signal.m_notify;
    return signal.m_name.AsCString("");
  }
}

bool UnixSignals::GetShouldSuppress(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_suppress;
  return false;
}

bool UnixSignals::SetShouldSuppress(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_suppress = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldSuppress(signo, value);
  return false;
}

bool UnixSignals::GetShouldStop(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_stop;
  return false;
}

bool UnixSignals::SetShouldStop(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_stop = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldStop(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldStop(signo, value);
  return false;
}

bool UnixSignals::GetShouldNotify(int signo) const {
  collection::const_iterator pos = m_signals.find(signo);
  if (pos != m_signals.end())
    return pos->second.m_notify;
  return false;
}

bool UnixSignals::SetShouldNotify(int signo, bool value) {
  collection::iterator pos = m_signals.find(signo);
  if (pos != m_signals.end()) {
    pos->second.m_notify = value;
    ++m_version;
    return true;
  }
  return false;
}

bool UnixSignals::SetShouldNotify(const char *signal_name, bool value) {
  const int32_t signo = GetSignalNumberFromName(signal_name);
  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
    return SetShouldNotify(signo, value);
  return false;
}

int32_t UnixSignals::GetNumSignals() const { return m_signals.size(); }

int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
  if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
    return LLDB_INVALID_SIGNAL_NUMBER;
  auto it = m_signals.begin();
  std::advance(it, index);
  return it->first;
}

uint64_t UnixSignals::GetVersion() const { return m_version; }

std::vector<int32_t>
UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
                                llvm::Optional<bool> should_stop,
                                llvm::Optional<bool> should_notify) {
  std::vector<int32_t> result;
  for (int32_t signo = GetFirstSignalNumber();
       signo != LLDB_INVALID_SIGNAL_NUMBER;
       signo = GetNextSignalNumber(signo)) {

    bool signal_suppress = false;
    bool signal_stop = false;
    bool signal_notify = false;
    GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);

    // If any of filtering conditions are not met, we move on to the next
    // signal.
    if (should_suppress.hasValue() &&
        signal_suppress != should_suppress.getValue())
      continue;

    if (should_stop.hasValue() && signal_stop != should_stop.getValue())
      continue;

    if (should_notify.hasValue() && signal_notify != should_notify.getValue())
      continue;

    result.push_back(signo);
  }

  return result;
}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright 2015 Cloudius Systems
 */
#include <cmath>
#include <seastar/core/reactor.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/sleep.hh>
#include <seastar/net/dns.hh>
#include "tls_echo_server.hh"

using namespace seastar;
namespace bpo = boost::program_options;

int main(int ac, char** av) {
    app_template app;
    app.add_options()
                    ("port", bpo::value<uint16_t>()->default_value(10000), "Server port")
                    ("address", bpo::value<std::string>()->default_value("127.0.0.1"), "Server address")
                    ("cert,c", bpo::value<std::string>()->required(), "Server certificate file")
                    ("key,k", bpo::value<std::string>()->required(), "Certificate key")
                    ("verbose,v", bpo::value<bool>()->default_value(false)->implicit_value(true), "Verbose")
                    ;
    return app.run_deprecated(ac, av, [&] {
        auto&& config = app.configuration();
        uint16_t port = config["port"].as<uint16_t>();
        auto crt = config["cert"].as<std::string>();
        auto key = config["key"].as<std::string>();
        auto addr = config["address"].as<std::string>();
        auto verbose = config["verbose"].as<bool>();

        std::cout << "Starting..." << std::endl;
        return net::dns::resolve_name(addr).then([=](net::inet_address a) {
            ipv4_addr ia(a, port);

            auto server = ::make_shared<seastar::sharded<echoserver>>();
            return server->start(verbose).then([=]() {
                return server->invoke_on_all(&echoserver::listen, socket_address(ia), sstring(crt), sstring(key), tls::client_auth::NONE);
            }).handle_exception([=](auto e) {
                std::cerr << "Error: " << e << std::endl;
                engine().exit(1);
            }).then([=] {
                std::cout << "TLS echo server running at " << addr << ":" << port << std::endl;
                engine().at_exit([server] {
                    return server->stop();
                });
            });
        });
    });
}
<commit_msg>tls_echo_server_demo: main: capture server post stop()<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright 2015 Cloudius Systems
 */
#include <cmath>
#include <seastar/core/reactor.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/sleep.hh>
#include <seastar/net/dns.hh>
#include "tls_echo_server.hh"

using namespace seastar;
namespace bpo = boost::program_options;

int main(int ac, char** av) {
    app_template app;
    app.add_options()
                    ("port", bpo::value<uint16_t>()->default_value(10000), "Server port")
                    ("address", bpo::value<std::string>()->default_value("127.0.0.1"), "Server address")
                    ("cert,c", bpo::value<std::string>()->required(), "Server certificate file")
                    ("key,k", bpo::value<std::string>()->required(), "Certificate key")
                    ("verbose,v", bpo::value<bool>()->default_value(false)->implicit_value(true), "Verbose")
                    ;
    return app.run_deprecated(ac, av, [&] {
        auto&& config = app.configuration();
        uint16_t port = config["port"].as<uint16_t>();
        auto crt = config["cert"].as<std::string>();
        auto key = config["key"].as<std::string>();
        auto addr = config["address"].as<std::string>();
        auto verbose = config["verbose"].as<bool>();

        std::cout << "Starting..." << std::endl;
        return net::dns::resolve_name(addr).then([=](net::inet_address a) {
            ipv4_addr ia(a, port);

            auto server = ::make_shared<seastar::sharded<echoserver>>();
            return server->start(verbose).then([=]() {
                return server->invoke_on_all(&echoserver::listen, socket_address(ia), sstring(crt), sstring(key), tls::client_auth::NONE);
            }).handle_exception([=](auto e) {
                std::cerr << "Error: " << e << std::endl;
                engine().exit(1);
            }).then([=] {
                std::cout << "TLS echo server running at " << addr << ":" << port << std::endl;
                engine().at_exit([server] {
                    return server->stop().finally([server] {});
                });
            });
        });
    });
}
<|endoftext|>


<commit_before>#ifndef slic3r_MeshUtils_hpp_
#define slic3r_MeshUtils_hpp_

#include "libslic3r/Point.hpp"
#include "libslic3r/Geometry.hpp"

#include <cfloat>

namespace Slic3r {

class TriangleMesh;
class TriangleMeshSlicer;

namespace GUI {

class Camera;

class ClippingPlane
{
    double m_data[4];

public:
    ClippingPlane()
    {
        m_data[0] = 0.0;
        m_data[1] = 0.0;
        m_data[2] = 1.0;
        m_data[3] = 0.0;
    }

    ClippingPlane(const Vec3d& direction, double offset)
    {
        Vec3d norm_dir = direction.normalized();
        m_data[0] = norm_dir(0);
        m_data[1] = norm_dir(1);
        m_data[2] = norm_dir(2);
        m_data[3] = offset;
    }

    bool operator==(const ClippingPlane& cp) const {
        return m_data[0]==cp.m_data[0] && m_data[1]==cp.m_data[1] && m_data[2]==cp.m_data[2] && m_data[3]==cp.m_data[3];
    }
    bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); }

    double distance(const Vec3d& pt) const {
        assert(is_approx(get_normal().norm(), 1.));
        return (-get_normal().dot(pt) + m_data[3]);
    }

    void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); }
    void set_offset(double offset) { m_data[3] = offset; }
    Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); }
    bool is_active() const { return m_data[3] != DBL_MAX; }
    static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); }
    const double* get_data() const { return m_data; }

    // Serialization through cereal library
    template <class Archive>
    void serialize( Archive & ar )
    {
        ar( m_data[0], m_data[1], m_data[2], m_data[3] );
    }
};

class MeshClipper {
public:
    void set_plane(const ClippingPlane& plane);
    void set_mesh(const TriangleMesh& mesh);
    void set_transformation(const Geometry::Transformation& trafo);

    const std::vector<Vec3f>& get_triangles();

private:
    void recalculate_triangles();

    Geometry::Transformation m_trafo;
    const TriangleMesh* m_mesh = nullptr;
    ClippingPlane m_plane;
    std::vector<Vec2f> m_triangles2d;
    std::vector<Vec3f> m_triangles3d;
    bool m_triangles_valid = false;
    std::unique_ptr<TriangleMeshSlicer> m_tms;
};

class MeshRaycaster {
public:
    MeshRaycaster(const TriangleMesh& mesh);
    ~MeshRaycaster();
    void set_transformation(const Geometry::Transformation& trafo);
    void set_camera(const Camera& camera);

    bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                           std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;

    std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
                                              const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const;

    Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;

private:
    // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
    class AABBWrapper;
    AABBWrapper* m_AABB_wrapper;
    const TriangleMesh* m_mesh = nullptr;
};

} // namespace GUI
} // namespace Slic3r

#endif // slic3r_MeshUtils_hpp_
<commit_msg>Fixed typo<commit_after>#ifndef slic3r_MeshUtils_hpp_
#define slic3r_MeshUtils_hpp_

#include "libslic3r/Point.hpp"
#include "libslic3r/Geometry.hpp"

#include <cfloat>

namespace Slic3r {

class TriangleMesh;
class TriangleMeshSlicer;

namespace GUI {

struct Camera;

class ClippingPlane
{
    double m_data[4];

public:
    ClippingPlane()
    {
        m_data[0] = 0.0;
        m_data[1] = 0.0;
        m_data[2] = 1.0;
        m_data[3] = 0.0;
    }

    ClippingPlane(const Vec3d& direction, double offset)
    {
        Vec3d norm_dir = direction.normalized();
        m_data[0] = norm_dir(0);
        m_data[1] = norm_dir(1);
        m_data[2] = norm_dir(2);
        m_data[3] = offset;
    }

    bool operator==(const ClippingPlane& cp) const {
        return m_data[0]==cp.m_data[0] && m_data[1]==cp.m_data[1] && m_data[2]==cp.m_data[2] && m_data[3]==cp.m_data[3];
    }
    bool operator!=(const ClippingPlane& cp) const { return ! (*this==cp); }

    double distance(const Vec3d& pt) const {
        assert(is_approx(get_normal().norm(), 1.));
        return (-get_normal().dot(pt) + m_data[3]);
    }

    void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); }
    void set_offset(double offset) { m_data[3] = offset; }
    Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); }
    bool is_active() const { return m_data[3] != DBL_MAX; }
    static ClippingPlane ClipsNothing() { return ClippingPlane(Vec3d(0., 0., 1.), DBL_MAX); }
    const double* get_data() const { return m_data; }

    // Serialization through cereal library
    template <class Archive>
    void serialize( Archive & ar )
    {
        ar( m_data[0], m_data[1], m_data[2], m_data[3] );
    }
};

class MeshClipper {
public:
    void set_plane(const ClippingPlane& plane);
    void set_mesh(const TriangleMesh& mesh);
    void set_transformation(const Geometry::Transformation& trafo);

    const std::vector<Vec3f>& get_triangles();

private:
    void recalculate_triangles();

    Geometry::Transformation m_trafo;
    const TriangleMesh* m_mesh = nullptr;
    ClippingPlane m_plane;
    std::vector<Vec2f> m_triangles2d;
    std::vector<Vec3f> m_triangles3d;
    bool m_triangles_valid = false;
    std::unique_ptr<TriangleMeshSlicer> m_tms;
};

class MeshRaycaster {
public:
    MeshRaycaster(const TriangleMesh& mesh);
    ~MeshRaycaster();
    void set_transformation(const Geometry::Transformation& trafo);
    void set_camera(const Camera& camera);

    bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
                           std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;

    std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
                                              const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const;

    Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;

private:
    // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here
    class AABBWrapper;
    AABBWrapper* m_AABB_wrapper;
    const TriangleMesh* m_mesh = nullptr;
};

} // namespace GUI
} // namespace Slic3r

#endif // slic3r_MeshUtils_hpp_
<|endoftext|>


<commit_before>#include "BluPrivatePCH.h"

UBluEye::UBluEye(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluEye::init()
{

	/**
	 * We don't want this running in editor unless it's PIE
	 * If we don't check this, CEF will spawn infinit processes with widget components
	 **/
	if (GEngine)
	{
		if (GEngine->IsEditor() && !GWorld->IsPlayInEditor())
		{
			UE_LOG(LogBlu, Log, TEXT("Notice: not playing - Component Will Not Initialize"));
			return;
		}
	}

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set the texture update region (for now the whole image)
	RenderParams.UpdateRegions = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height);

	// Set transparant option
	info.SetAsWindowless(0, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the default URL
	LoadURL(DefaultURL);
	ResetTexture();

}

void UBluEye::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8);
	Texture->AddToRoot();
	Texture->UpdateResource();

	RenderParams.Texture2DResource = (FTexture2DResource*)Texture->Resource;

	ResetMatInstance();

}

void UBluEye::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluEye::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
		return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
			void,
			const void*, ImageData, buffer,
			UTexture2D*, TargetTexture, Texture,
			int32, Stride, Width * 4,
			FBluTextureParams, Params, RenderParams,
			{

				RHIUpdateTexture2D(Params.Texture2DResource->GetTexture2DRHI(), 0, *Params.UpdateRegions, Stride, (uint8*)ImageData);

			});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluEye::ExecuteJS(const FString& code)
{
	CefString codeStr = *code;
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
}

void UBluEye::LoadURL(const FString& newURL)
{

	// Check if we want to load a local file

	if (newURL.Contains(TEXT("blui://"), ESearchCase::IgnoreCase, ESearchDir::FromStart))
	{

		// Get the current working directory
		FString GameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir());

		// We're loading a local file, so replace the proto with our game directory path
		FString LocalFile = newURL.Replace(TEXT("blui://"), *GameDir, ESearchCase::IgnoreCase);

		// Now we use the file proto
		LocalFile = FString(TEXT("file:///")) + LocalFile;

		UE_LOG(LogBlu, Log, TEXT("Load Local File: %s"), *LocalFile)

		// Load it up
		browser->GetMainFrame()->LoadURL(*LocalFile);

		return;

	}

	// Load as usual
	browser->GetMainFrame()->LoadURL(*newURL);

}

bool UBluEye::IsBrowserLoading()
{

	return browser->IsLoading();

}

void UBluEye::ReloadBrowser(bool IgnoreCache)
{

	if (IgnoreCache)
	{
		return browser->ReloadIgnoreCache();
	}

	browser->Reload();

}

void UBluEye::NavBack()
{

	if (browser->CanGoBack())
	{
		browser->GoBack();
	}

}

void UBluEye::NavForward()
{

	if (browser->CanGoForward())
	{
		browser->GoForward();
	}

}

void UBluEye::ResizeBrowser(int32 NewWidth, int32 NewHeight)
{

	// Disable the web view while we resize
	bEnabled = false;

	// Set our new Width and Height
	Width = NewWidth;
	Height = NewHeight;

	// Update our render handler
	renderer->width = NewWidth;
	renderer->height = NewHeight;

	// Also update the Region definition
	RenderParams.UpdateRegions->Height = NewHeight;
	RenderParams.UpdateRegions->Width = NewWidth;

	// Let the browser's host know we resized it
	browser->GetHost()->WasResized();

	// Now we can keep going
	bEnabled = true;

}

void UBluEye::TriggerMouseMove(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);

}

void UBluEye::TriggerLeftClick(const FVector2D& pos, const float scale)
{
	TriggerLeftMouseDown(pos, scale);
	TriggerLeftMouseUp(pos, scale);
}

void UBluEye::TriggerRightClick(const FVector2D& pos, const float scale)
{
	TriggerRightMouseDown(pos, scale);
	TriggerRightMouseUp(pos, scale);
}

void UBluEye::TriggerLeftMouseDown(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
}

void UBluEye::TriggerRightMouseDown(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
}

void UBluEye::TriggerLeftMouseUp(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
}

void UBluEye::TriggerRightMouseUp(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);
}

void UBluEye::TriggerMouseWheel(const float MouseWheelDelta, const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseWheelEvent(mouse_event, MouseWheelDelta * 10, MouseWheelDelta * 10);
}

void UBluEye::KeyDown(FKeyEvent InKey)
{

	processKeyMods(InKey);
	processKeyCode(InKey);

	key_event.type = KEYEVENT_KEYDOWN;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::KeyUp(FKeyEvent InKey)
{

	processKeyMods(InKey);
	processKeyCode(InKey);

	key_event.type = KEYEVENT_KEYUP;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::KeyPress(FKeyEvent InKey)
{

	// Simply trigger down, then up key events
	KeyDown(InKey);
	KeyUp(InKey);

}

void UBluEye::processKeyCode(FKeyEvent InKey)
{
	key_event.native_key_code = InKey.GetKeyCode();
	key_event.windows_key_code = InKey.GetKeyCode();
}

void UBluEye::CharKeyPress(FCharacterEvent CharEvent)
{

	// Process keymods like usual
	processKeyMods(CharEvent);

	// Below char input needs some special treatment, se we can't use the normal key down/up methods
	key_event.windows_key_code = CharEvent.GetCharacter();
	key_event.native_key_code = CharEvent.GetCharacter();
	key_event.type = KEYEVENT_CHAR;
	browser->GetHost()->SendKeyEvent(key_event);

	key_event.windows_key_code = CharEvent.GetCharacter();
	key_event.native_key_code = CharEvent.GetCharacter();

	key_event.type = KEYEVENT_KEYUP;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::RawCharKeyPress(const FString charToPress, bool isRepeat,
	bool LeftShiftDown,
	bool RightShiftDown,
	bool LeftControlDown,
	bool RightControlDown,
	bool LeftAltDown,
	bool RightAltDown,
	bool LeftCommandDown,
	bool RightCommandDown,
	bool CapsLocksOn)
{

	FModifierKeysState* KeyState = new FModifierKeysState(LeftShiftDown, RightShiftDown, LeftControlDown,
		RightControlDown, LeftAltDown, RightAltDown, LeftCommandDown, RightCommandDown, CapsLocksOn);

	FCharacterEvent* CharEvent = new FCharacterEvent(charToPress.GetCharArray()[0], *KeyState, 0, isRepeat);

	CharKeyPress(*CharEvent);

}

void UBluEye::SpecialKeyPress(EBluSpecialKeys key, bool LeftShiftDown,
	bool RightShiftDown,
	bool LeftControlDown,
	bool RightControlDown,
	bool LeftAltDown,
	bool RightAltDown,
	bool LeftCommandDown,
	bool RightCommandDown,
	bool CapsLocksOn)
{

	int32 keyValue = key;

	key_event.windows_key_code = keyValue;
	key_event.native_key_code = keyValue;
	key_event.type = KEYEVENT_KEYDOWN;
	browser->GetHost()->SendKeyEvent(key_event);

	key_event.windows_key_code = keyValue;
	key_event.native_key_code = keyValue;
	// bits 30 and 31 should be always 1 for WM_KEYUP
	key_event.type = KEYEVENT_KEYUP;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::processKeyMods(FInputEvent InKey)
{

	int mods = 0;

	// Test alt
	if (InKey.IsAltDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_ALT_DOWN;
	}
	else
	// Test control
	if (InKey.IsControlDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_CONTROL_DOWN;
	}
	else
	// Test shift
	if (InKey.IsShiftDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_SHIFT_DOWN;
	}

	key_event.modifiers = mods;

}

UTexture2D* UBluEye::GetTexture() const
{
	if (!Texture)
	{
		return UTexture2D::CreateTransient(Width, Height);
	}

	return Texture;
}

UMaterialInstanceDynamic* UBluEye::GetMaterialInstance() const
{
	return MaterialInstance;
}

void UBluEye::ResetMatInstance()
{
	if (!Texture || !BaseMaterial || TextureParameterName.IsNone())
	{
		return;
	}

	// Create material instance
	if (!MaterialInstance)
	{
		MaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, NULL);
		if (!MaterialInstance)
		{
			UE_LOG(LogBlu, Warning, TEXT("UI Material instance can't be created"));
			return;
		}
	}

	// Check again, we must have material instance
	if (!MaterialInstance)
	{
		UE_LOG(LogBlu, Error, TEXT("UI Material instance wasn't created"));
		return;
	}

	// Check we have desired parameter
	UTexture* Tex = nullptr;
	if (!MaterialInstance->GetTextureParameterValue(TextureParameterName, Tex))
	{
		UE_LOG(LogBlu, Warning, TEXT("UI Material instance Texture parameter not found"));
		return;
	}

	MaterialInstance->SetTextureParameterValue(TextureParameterName, GetTexture());
}

void UBluEye::CloseBrowser()
{
	BeginDestroy();
}

void UBluEye::BeginDestroy()
{

	if (browser)
	{

		// Make sure things stop playing, like audio, video, etc.
		LoadURL("about:blank");

		// Close up the browser
		browser->GetHost()->CloseDevTools();
		browser->GetHost()->CloseBrowser(true);

		UE_LOG(LogBlu, Warning, TEXT("Browser Closing"));

	}

	DestroyTexture();
	Super::BeginDestroy();

}<commit_msg>Clean up key char method<commit_after>#include "BluPrivatePCH.h"

UBluEye::UBluEye(const class FObjectInitializer& PCIP)
	: Super(PCIP)
{

	Width = 800;
	Height = 600;

	bIsTransparent = false;

}

void UBluEye::init()
{

	/**
	 * We don't want this running in editor unless it's PIE
	 * If we don't check this, CEF will spawn infinit processes with widget components
	 **/
	if (GEngine)
	{
		if (GEngine->IsEditor() && !GWorld->IsPlayInEditor())
		{
			UE_LOG(LogBlu, Log, TEXT("Notice: not playing - Component Will Not Initialize"));
			return;
		}
	}

	browserSettings.universal_access_from_file_urls = STATE_ENABLED;
	browserSettings.file_access_from_file_urls = STATE_ENABLED;

	info.width = Width;
	info.height = Height;

	// Set the texture update region (for now the whole image)
	RenderParams.UpdateRegions = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height);

	// Set transparant option
	info.SetAsWindowless(0, bIsTransparent);

	renderer = new RenderHandler(Width, Height, this);
	g_handler = new BrowserClient(renderer);
	browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL);

	// Setup JS event emitter
	g_handler->SetEventEmitter(&ScriptEventEmitter);

	UE_LOG(LogBlu, Log, TEXT("Component Initialized"));
	CefString str = *DefaultURL;
	UE_LOG(LogBlu, Log, TEXT("Loading URL: %s"), *DefaultURL);

	// Load the default URL
	LoadURL(DefaultURL);
	ResetTexture();

}

void UBluEye::ResetTexture()
{

	// Here we init the texture to its initial state
	DestroyTexture();

	// init the new Texture2D
	Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8);
	Texture->AddToRoot();
	Texture->UpdateResource();

	RenderParams.Texture2DResource = (FTexture2DResource*)Texture->Resource;

	ResetMatInstance();

}

void UBluEye::DestroyTexture()
{
	// Here we destory the texture and its resource
	if (Texture)
	{
		Texture->RemoveFromRoot();

		if (Texture->Resource)
		{
			BeginReleaseResource(Texture->Resource);
			FlushRenderingCommands();
		}

		Texture->MarkPendingKill();
		Texture = nullptr;
	}
}

void UBluEye::TextureUpdate(const void *buffer)
{
	if (!browser || !bEnabled)
	{
		UE_LOG(LogBlu, Warning, TEXT("NO BROWSER ACCESS OR NOT ENABLED"))
		return;
	}

	if (Texture && Texture->Resource)
	{

		// Is our texture ready?
		auto ref = static_cast<FTexture2DResource*>(Texture->Resource)->GetTexture2DRHI();
		if (!ref)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO REF"))
				return;
		}

		if (buffer == nullptr)
		{
			UE_LOG(LogBlu, Warning, TEXT("NO TEXTDATA"))
				return;
		}

		ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
			void,
			const void*, ImageData, buffer,
			UTexture2D*, TargetTexture, Texture,
			int32, Stride, Width * 4,
			FBluTextureParams, Params, RenderParams,
			{

				RHIUpdateTexture2D(Params.Texture2DResource->GetTexture2DRHI(), 0, *Params.UpdateRegions, Stride, (uint8*)ImageData);

			});

	}
	else {
		UE_LOG(LogBlu, Warning, TEXT("no Texture or Texture->resource"))
	}

}

void UBluEye::ExecuteJS(const FString& code)
{
	CefString codeStr = *code;
	browser->GetMainFrame()->ExecuteJavaScript(codeStr, "", 0);
}

void UBluEye::LoadURL(const FString& newURL)
{

	// Check if we want to load a local file

	if (newURL.Contains(TEXT("blui://"), ESearchCase::IgnoreCase, ESearchDir::FromStart))
	{

		// Get the current working directory
		FString GameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir());

		// We're loading a local file, so replace the proto with our game directory path
		FString LocalFile = newURL.Replace(TEXT("blui://"), *GameDir, ESearchCase::IgnoreCase);

		// Now we use the file proto
		LocalFile = FString(TEXT("file:///")) + LocalFile;

		UE_LOG(LogBlu, Log, TEXT("Load Local File: %s"), *LocalFile)

		// Load it up
		browser->GetMainFrame()->LoadURL(*LocalFile);

		return;

	}

	// Load as usual
	browser->GetMainFrame()->LoadURL(*newURL);

}

bool UBluEye::IsBrowserLoading()
{

	return browser->IsLoading();

}

void UBluEye::ReloadBrowser(bool IgnoreCache)
{

	if (IgnoreCache)
	{
		return browser->ReloadIgnoreCache();
	}

	browser->Reload();

}

void UBluEye::NavBack()
{

	if (browser->CanGoBack())
	{
		browser->GoBack();
	}

}

void UBluEye::NavForward()
{

	if (browser->CanGoForward())
	{
		browser->GoForward();
	}

}

void UBluEye::ResizeBrowser(int32 NewWidth, int32 NewHeight)
{

	// Disable the web view while we resize
	bEnabled = false;

	// Set our new Width and Height
	Width = NewWidth;
	Height = NewHeight;

	// Update our render handler
	renderer->width = NewWidth;
	renderer->height = NewHeight;

	// Also update the Region definition
	RenderParams.UpdateRegions->Height = NewHeight;
	RenderParams.UpdateRegions->Width = NewWidth;

	// Let the browser's host know we resized it
	browser->GetHost()->WasResized();

	// Now we can keep going
	bEnabled = true;

}

void UBluEye::TriggerMouseMove(const FVector2D& pos, const float scale)
{

	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendFocusEvent(true);
	browser->GetHost()->SendMouseMoveEvent(mouse_event, false);

}

void UBluEye::TriggerLeftClick(const FVector2D& pos, const float scale)
{
	TriggerLeftMouseDown(pos, scale);
	TriggerLeftMouseUp(pos, scale);
}

void UBluEye::TriggerRightClick(const FVector2D& pos, const float scale)
{
	TriggerRightMouseDown(pos, scale);
	TriggerRightMouseUp(pos, scale);
}

void UBluEye::TriggerLeftMouseDown(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
}

void UBluEye::TriggerRightMouseDown(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
}

void UBluEye::TriggerLeftMouseUp(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
}

void UBluEye::TriggerRightMouseUp(const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);
}

void UBluEye::TriggerMouseWheel(const float MouseWheelDelta, const FVector2D& pos, const float scale)
{
	mouse_event.x = pos.X / scale;
	mouse_event.y = pos.Y / scale;

	browser->GetHost()->SendMouseWheelEvent(mouse_event, MouseWheelDelta * 10, MouseWheelDelta * 10);
}

void UBluEye::KeyDown(FKeyEvent InKey)
{

	processKeyMods(InKey);
	processKeyCode(InKey);

	key_event.type = KEYEVENT_KEYDOWN;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::KeyUp(FKeyEvent InKey)
{

	processKeyMods(InKey);
	processKeyCode(InKey);

	key_event.type = KEYEVENT_KEYUP;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::KeyPress(FKeyEvent InKey)
{

	// Simply trigger down, then up key events
	KeyDown(InKey);
	KeyUp(InKey);

}

void UBluEye::processKeyCode(FKeyEvent InKey)
{
	key_event.native_key_code = InKey.GetKeyCode();
	key_event.windows_key_code = InKey.GetKeyCode();
}

void UBluEye::CharKeyPress(FCharacterEvent CharEvent)
{

	// Process keymods like usual
	processKeyMods(CharEvent);

	// Below char input needs some special treatment, se we can't use the normal key down/up methods

	key_event.windows_key_code = CharEvent.GetCharacter();
	key_event.native_key_code = CharEvent.GetCharacter();
	key_event.type = KEYEVENT_CHAR;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::RawCharKeyPress(const FString charToPress, bool isRepeat,
	bool LeftShiftDown,
	bool RightShiftDown,
	bool LeftControlDown,
	bool RightControlDown,
	bool LeftAltDown,
	bool RightAltDown,
	bool LeftCommandDown,
	bool RightCommandDown,
	bool CapsLocksOn)
{

	FModifierKeysState* KeyState = new FModifierKeysState(LeftShiftDown, RightShiftDown, LeftControlDown,
		RightControlDown, LeftAltDown, RightAltDown, LeftCommandDown, RightCommandDown, CapsLocksOn);

	FCharacterEvent* CharEvent = new FCharacterEvent(charToPress.GetCharArray()[0], *KeyState, 0, isRepeat);

	CharKeyPress(*CharEvent);

}

void UBluEye::SpecialKeyPress(EBluSpecialKeys key, bool LeftShiftDown,
	bool RightShiftDown,
	bool LeftControlDown,
	bool RightControlDown,
	bool LeftAltDown,
	bool RightAltDown,
	bool LeftCommandDown,
	bool RightCommandDown,
	bool CapsLocksOn)
{

	int32 keyValue = key;

	key_event.windows_key_code = keyValue;
	key_event.native_key_code = keyValue;
	key_event.type = KEYEVENT_KEYDOWN;
	browser->GetHost()->SendKeyEvent(key_event);

	key_event.windows_key_code = keyValue;
	key_event.native_key_code = keyValue;
	// bits 30 and 31 should be always 1 for WM_KEYUP
	key_event.type = KEYEVENT_KEYUP;
	browser->GetHost()->SendKeyEvent(key_event);

}

void UBluEye::processKeyMods(FInputEvent InKey)
{

	int mods = 0;

	// Test alt
	if (InKey.IsAltDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_ALT_DOWN;
	}
	else
	// Test control
	if (InKey.IsControlDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_CONTROL_DOWN;
	}
	else
	// Test shift
	if (InKey.IsShiftDown())
	{
		mods |= cef_event_flags_t::EVENTFLAG_SHIFT_DOWN;
	}

	key_event.modifiers = mods;

}

UTexture2D* UBluEye::GetTexture() const
{
	if (!Texture)
	{
		return UTexture2D::CreateTransient(Width, Height);
	}

	return Texture;
}

UMaterialInstanceDynamic* UBluEye::GetMaterialInstance() const
{
	return MaterialInstance;
}

void UBluEye::ResetMatInstance()
{
	if (!Texture || !BaseMaterial || TextureParameterName.IsNone())
	{
		return;
	}

	// Create material instance
	if (!MaterialInstance)
	{
		MaterialInstance = UMaterialInstanceDynamic::Create(BaseMaterial, NULL);
		if (!MaterialInstance)
		{
			UE_LOG(LogBlu, Warning, TEXT("UI Material instance can't be created"));
			return;
		}
	}

	// Check again, we must have material instance
	if (!MaterialInstance)
	{
		UE_LOG(LogBlu, Error, TEXT("UI Material instance wasn't created"));
		return;
	}

	// Check we have desired parameter
	UTexture* Tex = nullptr;
	if (!MaterialInstance->GetTextureParameterValue(TextureParameterName, Tex))
	{
		UE_LOG(LogBlu, Warning, TEXT("UI Material instance Texture parameter not found"));
		return;
	}

	MaterialInstance->SetTextureParameterValue(TextureParameterName, GetTexture());
}

void UBluEye::CloseBrowser()
{
	BeginDestroy();
}

void UBluEye::BeginDestroy()
{

	if (browser)
	{

		// Make sure things stop playing, like audio, video, etc.
		LoadURL("about:blank");

		// Close up the browser
		browser->GetHost()->CloseDevTools();
		browser->GetHost()->CloseBrowser(true);

		UE_LOG(LogBlu, Warning, TEXT("Browser Closing"));

	}

	DestroyTexture();
	Super::BeginDestroy();

}<|endoftext|>


<commit_before>#include "fontContext.h"

#include "platform.h"

#define SDF_IMPLEMENTATION
#include "sdf.h"

#include <memory>

#define DEFAULT "fonts/NotoSans-Regular.ttf"
#define FONT_AR "fonts/NotoNaskh-Regular.ttf"
#define FONT_HE "fonts/NotoSansHebrew-Regular.ttf"
#define FONT_JA "fonts/DroidSansJapanese.ttf"
#define FALLBACK "fonts/DroidSansFallback.ttf"

#if defined(PLATFORM_ANDROID)
#define ANDROID_FONT_PATH "/system/fonts/"
#endif
#define BASE_SIZE 16
#define STEP_SIZE 12

#define SDF_WIDTH 6

#define MIN_LINE_WIDTH 4

namespace Tangram {

FontContext::FontContext() :
    m_sdfRadius(SDF_WIDTH),
    m_atlas(*this, GlyphTexture::size, m_sdfRadius),
    m_batch(m_atlas, m_scratch),
    m_sceneResourceRoot("") {

// TODO: make this platform independent
#if defined(PLATFORM_ANDROID)
    auto fontPath = systemFontPath("sans-serif", "400", "normal");
    LOG("FONT %s", fontPath.c_str());

    int size = BASE_SIZE;
    for (int i = 0; i < 3; i++, size += STEP_SIZE) {
        m_font[i] = m_alfons.addFont("default", alfons::InputSource(fontPath), size);
    }

    std::string fallback = "";
    int importance = 0;

    while (importance < 100) {
        fallback = systemFontFallbackPath(importance++, 400);
        if (fallback.empty()) { break; }

        if (fallback.find("UI-") != std::string::npos) {
            continue;
        }
        fontPath = ANDROID_FONT_PATH;
        fontPath += fallback;
        LOG("FALLBACK %s", fontPath.c_str());

        int size = BASE_SIZE;
        for (int i = 0; i < 3; i++, size += STEP_SIZE) {
            m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(fontPath), size));
        }
    }
#elif defined(PLATFORM_IOS)

    int size = BASE_SIZE;
    auto loadFonts = [&](const char* path) {
        unsigned int dataSize;
        char* data = reinterpret_cast<char*>(bytesFromFile(path, PathType::resource, &dataSize,
                    m_sceneResourceRoot.c_str()));
        if (data) {
            for (int i = 0; i < 3; i++, size += STEP_SIZE) {
                m_font[i] = m_alfons.addFont("default", alfons::InputSource(data, dataSize), size);
            }
            free(data);
        }
    };
    auto addFaces = [&](const char* path) {
        unsigned int dataSize;
        char* data = reinterpret_cast<char*>(bytesFromFile(path, PathType::resource, &dataSize,
                    m_sceneResourceRoot.c_str()));
        if (data) {
            for (int i = 0; i < 3; i++, size += STEP_SIZE) {
                    m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(data, dataSize), size));
            }
            free(data);
        }
    };

    loadFonts(DEFAULT);
    addFaces(FONT_AR);
    addFaces(FONT_HE);
    addFaces(FONT_JA);
    addFaces(FALLBACK);

#else
    int size = BASE_SIZE;
    for (int i = 0; i < 3; i++, size += STEP_SIZE) {
        m_font[i] = m_alfons.addFont("default", alfons::InputSource(DEFAULT), size);
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_AR), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_HE), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_JA), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FALLBACK), size));
    }
#endif
}

// Synchronized on m_mutex in layoutText(), called on tile-worker threads
void FontContext::addTexture(alfons::AtlasID id, uint16_t width, uint16_t height) {
    if (m_textures.size() == max_textures) {
        LOGE("Way too many glyph textures!");
        return;
    }
    m_textures.emplace_back();
}

// Synchronized on m_mutex in layoutText(), called on tile-worker threads
void FontContext::addGlyph(alfons::AtlasID id, uint16_t gx, uint16_t gy, uint16_t gw, uint16_t gh,
                           const unsigned char* src, uint16_t pad) {

    if (id >= max_textures) { return; }

    auto& texData = m_textures[id].texData;
    auto& texture = m_textures[id].texture;
    m_textures[id].dirty = true;

    uint16_t stride = GlyphTexture::size;
    uint16_t width =  GlyphTexture::size;

    unsigned char* dst = &texData[(gx + pad) + (gy + pad) * stride];

    for (size_t y = 0, pos = 0; y < gh; y++, pos += gw) {
        std::memcpy(dst + y * stride, src + pos, gw);
    }

    dst = &texData[gx + gy * width];
    gw += pad * 2;
    gh += pad * 2;

    size_t bytes = gw * gh * sizeof(float) * 3;
    if (m_sdfBuffer.size() < bytes) {
        m_sdfBuffer.resize(bytes);
    }

    sdfBuildDistanceFieldNoAlloc(dst, width, m_sdfRadius,
                                 dst, gw, gh, width,
                                 &m_sdfBuffer[0]);

    texture.setDirty(gy, gh);
}

void FontContext::releaseAtlas(std::bitset<max_textures> _refs) {
    if (!_refs.any()) { return; }
    std::lock_guard<std::mutex> lock(m_mutex);
    for (size_t i = 0; i < m_textures.size(); i++) {
        if (!_refs[i]) { continue; }

        if (--m_atlasRefCount[i] == 0) {
            LOGD("CLEAR ATLAS %d", i);
            m_atlas.clear(i);
            m_textures[i].texData.assign(GlyphTexture::size * GlyphTexture::size, 0);
        }
    }
}

void FontContext::updateTextures() {
    std::lock_guard<std::mutex> lock(m_mutex);

    for (auto& gt : m_textures) {
        if (gt.dirty || !gt.texture.isValid()) {
            gt.dirty = false;
            auto td = reinterpret_cast<const GLuint*>(gt.texData.data());
            gt.texture.update(0, td);
        }
    }
}

void FontContext::bindTexture(alfons::AtlasID _id, GLuint _unit) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_textures[_id].texture.bind(_unit);

}

bool FontContext::layoutText(TextStyle::Parameters& _params, const std::string& _text,
                             std::vector<GlyphQuad>& _quads, std::bitset<max_textures>& _refs, glm::vec2& _size) {

    std::lock_guard<std::mutex> lock(m_mutex);

    alfons::LineLayout line = m_shaper.shape(_params.font, _text);

    if (line.shapes().size() == 0) {
        LOGD("Empty text line");
        return false;
    }

    line.setScale(_params.fontScale);

    // m_batch.drawShapeRange() calls FontContext's TextureCallback for new glyphs
    // and MeshCallback (drawGlyph) for vertex quads of each glyph in LineLayout.

    m_scratch.quads = &_quads;

    size_t quadsStart = _quads.size();
    alfons::LineMetrics metrics;

    if (_params.wordWrap) {
        m_textWrapper.draw(m_batch, line, MIN_LINE_WIDTH,
                           _params.maxLineWidth, _params.align,
                           _params.lineSpacing, metrics);
    } else {
        glm::vec2 position(0);
        m_batch.drawShapeRange(line, 0, line.shapes().size(), position, metrics);
    }

    // TextLabel parameter: Dimension
    float width = metrics.aabb.z - metrics.aabb.x;
    float height = metrics.aabb.w - metrics.aabb.y;

    // Offset to center all glyphs around 0/0
    glm::vec2 offset((metrics.aabb.x + width * 0.5) * TextVertex::position_scale,
                     (metrics.aabb.y + height * 0.5) * TextVertex::position_scale);

    auto it = _quads.begin() + quadsStart;
    if (it == _quads.end()) {
        // No glyphs added
        return false;
    }

    while (it != _quads.end()) {

        if (!_refs[it->atlas]) {
            _refs[it->atlas] = true;
            m_atlasRefCount[it->atlas]++;
        }

        it->quad[0].pos -= offset;
        it->quad[1].pos -= offset;
        it->quad[2].pos -= offset;
        it->quad[3].pos -= offset;
        ++it;
    }

    _size = glm::vec2(width, height);

    return true;
}

void FontContext::ScratchBuffer::drawGlyph(const alfons::Rect& q, const alfons::AtlasGlyph& atlasGlyph) {
    if (atlasGlyph.atlas >= max_textures) { return; }

    auto& g = *atlasGlyph.glyph;
    quads->push_back({
            atlasGlyph.atlas,
            {{glm::vec2{q.x1, q.y1} * TextVertex::position_scale, {g.u1, g.v1}},
             {glm::vec2{q.x1, q.y2} * TextVertex::position_scale, {g.u1, g.v2}},
             {glm::vec2{q.x2, q.y1} * TextVertex::position_scale, {g.u2, g.v1}},
             {glm::vec2{q.x2, q.y2} * TextVertex::position_scale, {g.u2, g.v2}}}});
}

auto FontContext::getFont(const std::string& _family, const std::string& _style,
                          const std::string& _weight, float _size) -> std::shared_ptr<alfons::Font> {

    int sizeIndex = 0;

    // Pick the smallest font that does not scale down too much
    float fontSize = BASE_SIZE;
    for (int i = 0; i < 3; i++) {
        sizeIndex = i;

        if (_size <= fontSize) { break; }
        fontSize += STEP_SIZE;
    }
    //LOG(">> %f - %d ==> %f", _size, sizeIndex, _size / ((sizeIndex+1) * BASE_SIZE));

    std::lock_guard<std::mutex> lock(m_mutex);

    static std::string fontName;

    fontName.clear();
    fontName += _family;
    fontName += '_';
    fontName += _weight;
    fontName += '_';
    fontName += _style;

    auto font = m_alfons.getFont(fontName, fontSize);
    if (font->hasFaces()) { return font; }

    unsigned int dataSize = 0;
    unsigned char* data = nullptr;

    // Assuming bundled ttf file follows this convention
    auto bundledFontPath = "fonts/" + _family + "-" + _weight + _style + ".ttf";
    if (!(data = bytesFromFile(bundledFontPath.c_str(), PathType::resource, &dataSize, m_sceneResourceRoot.c_str())) &&
        !(data = bytesFromFile(bundledFontPath.c_str(), PathType::internal, &dataSize, m_sceneResourceRoot.c_str()))) {
        const std::string sysFontPath = systemFontPath(_family, _weight, _style);
        if (!(data = bytesFromFile(sysFontPath.c_str(), PathType::absolute, &dataSize, m_sceneResourceRoot.c_str())) ) {

            LOGE("Could not load font file %s", fontName.c_str());
            // add fallbacks from default font
            font->addFaces(*m_font[sizeIndex]);
            return font;
        }
    }

    font->addFace(m_alfons.addFontFace(alfons::InputSource(reinterpret_cast<char*>(data), dataSize), fontSize));
    free(data);

    // add fallbacks from default font
    font->addFaces(*m_font[sizeIndex]);

    return font;
}

}
<commit_msg>LOG => LOGD<commit_after>#include "fontContext.h"

#include "platform.h"

#define SDF_IMPLEMENTATION
#include "sdf.h"

#include <memory>

#define DEFAULT "fonts/NotoSans-Regular.ttf"
#define FONT_AR "fonts/NotoNaskh-Regular.ttf"
#define FONT_HE "fonts/NotoSansHebrew-Regular.ttf"
#define FONT_JA "fonts/DroidSansJapanese.ttf"
#define FALLBACK "fonts/DroidSansFallback.ttf"

#if defined(PLATFORM_ANDROID)
#define ANDROID_FONT_PATH "/system/fonts/"
#endif
#define BASE_SIZE 16
#define STEP_SIZE 12

#define SDF_WIDTH 6

#define MIN_LINE_WIDTH 4

namespace Tangram {

FontContext::FontContext() :
    m_sdfRadius(SDF_WIDTH),
    m_atlas(*this, GlyphTexture::size, m_sdfRadius),
    m_batch(m_atlas, m_scratch),
    m_sceneResourceRoot("") {

// TODO: make this platform independent
#if defined(PLATFORM_ANDROID)
    auto fontPath = systemFontPath("sans-serif", "400", "normal");
    LOGD("FONT %s", fontPath.c_str());

    int size = BASE_SIZE;
    for (int i = 0; i < 3; i++, size += STEP_SIZE) {
        m_font[i] = m_alfons.addFont("default", alfons::InputSource(fontPath), size);
    }

    std::string fallback = "";
    int importance = 0;

    while (importance < 100) {
        fallback = systemFontFallbackPath(importance++, 400);
        if (fallback.empty()) { break; }

        if (fallback.find("UI-") != std::string::npos) {
            continue;
        }
        fontPath = ANDROID_FONT_PATH;
        fontPath += fallback;
        LOGD("FALLBACK %s", fontPath.c_str());

        int size = BASE_SIZE;
        for (int i = 0; i < 3; i++, size += STEP_SIZE) {
            m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(fontPath), size));
        }
    }
#elif defined(PLATFORM_IOS)

    int size = BASE_SIZE;
    auto loadFonts = [&](const char* path) {
        unsigned int dataSize;
        char* data = reinterpret_cast<char*>(bytesFromFile(path, PathType::resource, &dataSize,
                    m_sceneResourceRoot.c_str()));
        if (data) {
            for (int i = 0; i < 3; i++, size += STEP_SIZE) {
                m_font[i] = m_alfons.addFont("default", alfons::InputSource(data, dataSize), size);
            }
            free(data);
        }
    };
    auto addFaces = [&](const char* path) {
        unsigned int dataSize;
        char* data = reinterpret_cast<char*>(bytesFromFile(path, PathType::resource, &dataSize,
                    m_sceneResourceRoot.c_str()));
        if (data) {
            for (int i = 0; i < 3; i++, size += STEP_SIZE) {
                    m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(data, dataSize), size));
            }
            free(data);
        }
    };

    loadFonts(DEFAULT);
    addFaces(FONT_AR);
    addFaces(FONT_HE);
    addFaces(FONT_JA);
    addFaces(FALLBACK);

#else
    int size = BASE_SIZE;
    for (int i = 0; i < 3; i++, size += STEP_SIZE) {
        m_font[i] = m_alfons.addFont("default", alfons::InputSource(DEFAULT), size);
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_AR), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_HE), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FONT_JA), size));
        m_font[i]->addFace(m_alfons.addFontFace(alfons::InputSource(FALLBACK), size));
    }
#endif
}

// Synchronized on m_mutex in layoutText(), called on tile-worker threads
void FontContext::addTexture(alfons::AtlasID id, uint16_t width, uint16_t height) {
    if (m_textures.size() == max_textures) {
        LOGE("Way too many glyph textures!");
        return;
    }
    m_textures.emplace_back();
}

// Synchronized on m_mutex in layoutText(), called on tile-worker threads
void FontContext::addGlyph(alfons::AtlasID id, uint16_t gx, uint16_t gy, uint16_t gw, uint16_t gh,
                           const unsigned char* src, uint16_t pad) {

    if (id >= max_textures) { return; }

    auto& texData = m_textures[id].texData;
    auto& texture = m_textures[id].texture;
    m_textures[id].dirty = true;

    uint16_t stride = GlyphTexture::size;
    uint16_t width =  GlyphTexture::size;

    unsigned char* dst = &texData[(gx + pad) + (gy + pad) * stride];

    for (size_t y = 0, pos = 0; y < gh; y++, pos += gw) {
        std::memcpy(dst + y * stride, src + pos, gw);
    }

    dst = &texData[gx + gy * width];
    gw += pad * 2;
    gh += pad * 2;

    size_t bytes = gw * gh * sizeof(float) * 3;
    if (m_sdfBuffer.size() < bytes) {
        m_sdfBuffer.resize(bytes);
    }

    sdfBuildDistanceFieldNoAlloc(dst, width, m_sdfRadius,
                                 dst, gw, gh, width,
                                 &m_sdfBuffer[0]);

    texture.setDirty(gy, gh);
}

void FontContext::releaseAtlas(std::bitset<max_textures> _refs) {
    if (!_refs.any()) { return; }
    std::lock_guard<std::mutex> lock(m_mutex);
    for (size_t i = 0; i < m_textures.size(); i++) {
        if (!_refs[i]) { continue; }

        if (--m_atlasRefCount[i] == 0) {
            LOGD("CLEAR ATLAS %d", i);
            m_atlas.clear(i);
            m_textures[i].texData.assign(GlyphTexture::size * GlyphTexture::size, 0);
        }
    }
}

void FontContext::updateTextures() {
    std::lock_guard<std::mutex> lock(m_mutex);

    for (auto& gt : m_textures) {
        if (gt.dirty || !gt.texture.isValid()) {
            gt.dirty = false;
            auto td = reinterpret_cast<const GLuint*>(gt.texData.data());
            gt.texture.update(0, td);
        }
    }
}

void FontContext::bindTexture(alfons::AtlasID _id, GLuint _unit) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_textures[_id].texture.bind(_unit);

}

bool FontContext::layoutText(TextStyle::Parameters& _params, const std::string& _text,
                             std::vector<GlyphQuad>& _quads, std::bitset<max_textures>& _refs, glm::vec2& _size) {

    std::lock_guard<std::mutex> lock(m_mutex);

    alfons::LineLayout line = m_shaper.shape(_params.font, _text);

    if (line.shapes().size() == 0) {
        LOGD("Empty text line");
        return false;
    }

    line.setScale(_params.fontScale);

    // m_batch.drawShapeRange() calls FontContext's TextureCallback for new glyphs
    // and MeshCallback (drawGlyph) for vertex quads of each glyph in LineLayout.

    m_scratch.quads = &_quads;

    size_t quadsStart = _quads.size();
    alfons::LineMetrics metrics;

    if (_params.wordWrap) {
        m_textWrapper.draw(m_batch, line, MIN_LINE_WIDTH,
                           _params.maxLineWidth, _params.align,
                           _params.lineSpacing, metrics);
    } else {
        glm::vec2 position(0);
        m_batch.drawShapeRange(line, 0, line.shapes().size(), position, metrics);
    }

    // TextLabel parameter: Dimension
    float width = metrics.aabb.z - metrics.aabb.x;
    float height = metrics.aabb.w - metrics.aabb.y;

    // Offset to center all glyphs around 0/0
    glm::vec2 offset((metrics.aabb.x + width * 0.5) * TextVertex::position_scale,
                     (metrics.aabb.y + height * 0.5) * TextVertex::position_scale);

    auto it = _quads.begin() + quadsStart;
    if (it == _quads.end()) {
        // No glyphs added
        return false;
    }

    while (it != _quads.end()) {

        if (!_refs[it->atlas]) {
            _refs[it->atlas] = true;
            m_atlasRefCount[it->atlas]++;
        }

        it->quad[0].pos -= offset;
        it->quad[1].pos -= offset;
        it->quad[2].pos -= offset;
        it->quad[3].pos -= offset;
        ++it;
    }

    _size = glm::vec2(width, height);

    return true;
}

void FontContext::ScratchBuffer::drawGlyph(const alfons::Rect& q, const alfons::AtlasGlyph& atlasGlyph) {
    if (atlasGlyph.atlas >= max_textures) { return; }

    auto& g = *atlasGlyph.glyph;
    quads->push_back({
            atlasGlyph.atlas,
            {{glm::vec2{q.x1, q.y1} * TextVertex::position_scale, {g.u1, g.v1}},
             {glm::vec2{q.x1, q.y2} * TextVertex::position_scale, {g.u1, g.v2}},
             {glm::vec2{q.x2, q.y1} * TextVertex::position_scale, {g.u2, g.v1}},
             {glm::vec2{q.x2, q.y2} * TextVertex::position_scale, {g.u2, g.v2}}}});
}

auto FontContext::getFont(const std::string& _family, const std::string& _style,
                          const std::string& _weight, float _size) -> std::shared_ptr<alfons::Font> {

    int sizeIndex = 0;

    // Pick the smallest font that does not scale down too much
    float fontSize = BASE_SIZE;
    for (int i = 0; i < 3; i++) {
        sizeIndex = i;

        if (_size <= fontSize) { break; }
        fontSize += STEP_SIZE;
    }
    //LOG(">> %f - %d ==> %f", _size, sizeIndex, _size / ((sizeIndex+1) * BASE_SIZE));

    std::lock_guard<std::mutex> lock(m_mutex);

    static std::string fontName;

    fontName.clear();
    fontName += _family;
    fontName += '_';
    fontName += _weight;
    fontName += '_';
    fontName += _style;

    auto font = m_alfons.getFont(fontName, fontSize);
    if (font->hasFaces()) { return font; }

    unsigned int dataSize = 0;
    unsigned char* data = nullptr;

    // Assuming bundled ttf file follows this convention
    auto bundledFontPath = "fonts/" + _family + "-" + _weight + _style + ".ttf";
    if (!(data = bytesFromFile(bundledFontPath.c_str(), PathType::resource, &dataSize, m_sceneResourceRoot.c_str())) &&
        !(data = bytesFromFile(bundledFontPath.c_str(), PathType::internal, &dataSize, m_sceneResourceRoot.c_str()))) {
        const std::string sysFontPath = systemFontPath(_family, _weight, _style);
        if (!(data = bytesFromFile(sysFontPath.c_str(), PathType::absolute, &dataSize, m_sceneResourceRoot.c_str())) ) {

            LOGE("Could not load font file %s", fontName.c_str());
            // add fallbacks from default font
            font->addFaces(*m_font[sizeIndex]);
            return font;
        }
    }

    font->addFace(m_alfons.addFontFace(alfons::InputSource(reinterpret_cast<char*>(data), dataSize), fontSize));
    free(data);

    // add fallbacks from default font
    font->addFaces(*m_font[sizeIndex]);

    return font;
}

}
<|endoftext|>


<commit_before><commit_msg>Verbose view now shows track-level data<commit_after><|endoftext|>


<commit_before><commit_msg>added missing function implementation<commit_after><|endoftext|>