<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <csetjmp>

#include <base/os.h>
#include <base/test/task_test_util.h>

#include <cmn/agent_cmn.h>
#include <cmn/agent_factory.h>
#include <init/agent_param.h>
#include <cfg/cfg_init.h>
#include <ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h>

#include <oper/operdb_init.h>
#include <vrouter/ksync/ksync_init.h>
#include <vrouter/ksync/test/ksync_test.h>
#include <uve/agent_uve.h>
#include <uve/test/agent_uve_test.h>
#include "test/test_init.h"
#include <test/test_agent_init.h>
#include "test_ovs_agent_init.h"
#include "test-xml/test_xml_oper.h"
#include "test_xml_physical_device.h"
#include "test_xml_ovsdb.h"

#include <boost/filesystem/operations.hpp>

#define OVSDB_SERVER "build/third_party/openvswitch/ovsdb/ovsdb-server"
#define DB_FILE_TEMPLATE "controller/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/vtep.db"

using namespace OVSDB;
std::string db_file_name;
std::string lock_file_name;
bool server_inited = false;
bool server_stopping = false;
int server_pid;
jmp_buf env;
uint32_t ovsdb_port = 0;

void stop_ovsdb_server() {
    if (server_inited == false || server_stopping == true) {
        return;
    }
    server_stopping = true;
    kill(server_pid, SIGTERM);
    int status;
    while (server_pid != wait(&status));
    // after the child process has exited, delete the db file and lock file
    boost::filesystem::remove(db_file_name);
    boost::filesystem::remove(lock_file_name);
    server_inited = false;
    server_stopping = false;
}

void signalHandler(int sig_num) {
    stop_ovsdb_server();
    longjmp (env, 1);
}

static void start_ovsdb_server() {
    assert(server_inited == false);
    signal(SIGABRT, signalHandler);
    signal(SIGSEGV, signalHandler);
    signal(SIGTERM, signalHandler);
    atexit(stop_ovsdb_server);
    server_inited = true;
    db_file_name =
        "build/debug/vnsw/agent/ovs_tor_agent/ovsdb_client/test/vtep_" +
        boost::lexical_cast<std::string>(getpid()) + "_" +
        boost::lexical_cast<std::string>(UTCTimestampUsec()) + ".db";
    lock_file_name = db_file_name;
    size_t pos = lock_file_name.find("vtep_");
    lock_file_name.insert(pos, ".");
    lock_file_name.append(".~lock~");
    // create a new DB for Ovsdb Server from DB Template file
    boost::filesystem::copy_file(DB_FILE_TEMPLATE, db_file_name);
    server_pid = fork();

    if (server_pid == 0) {
        execlp(OVSDB_SERVER, OVSDB_SERVER, "--remote=ptcp:0:127.0.0.1",
               db_file_name.c_str(), static_cast<char *>(NULL));
    }

    std::string port = "";
    // Get the TCP server port used by ovsdb-server.
    int count = 0;
    do {
        usleep(1000);
        assert(count < 10000);
        count++;
        std::string cmd("netstat -anp | grep tcp | grep ");
        cmd += boost::lexical_cast<std::string>(server_pid);
        cmd += "/ovsdb-server";
        FILE* pipe = popen(cmd.c_str(), "r");
        if (!pipe) assert(false);
        char buffer[128];
        std::string result;
        while(!feof(pipe)) {
            if(fgets(buffer, 128, pipe) != NULL)
                result += buffer;
        }
        pclose(pipe);
        size_t start = result.find("127.0.0.1:");
        // find will fail if the process has not started the listen on socket
        if (start == string::npos)
            continue;
        start += 10;
        size_t end = result.find_first_of(' ', start);
        assert(end != string::npos);
        port = result.substr(start, end - start);
    } while (port.empty());
    ovsdb_port = strtoul(port.c_str(), NULL, 0);
}

OvsdbClientTcpSessionTest::OvsdbClientTcpSessionTest(Agent *agent,
                                                     OvsPeerManager *manager,
                                                     TcpServer *server,
                                                     Socket *sock,
                                                     bool async_ready)
    : OvsdbClientTcpSession(agent, manager, server, sock, async_ready) {
}

OvsdbClientTcpSessionTest::~OvsdbClientTcpSessionTest() {
}

OvsdbClientTcpTest::OvsdbClientTcpTest(Agent *agent, IpAddress tor_ip,
                                       int tor_port, IpAddress tsn_ip,
                                       int keepalive, OvsPeerManager *manager)
    : OvsdbClientTcp(agent, tor_ip, tor_port, tsn_ip, keepalive, -1, manager),
    enable_connect_(true) {
}

OvsdbClientTcpTest::~OvsdbClientTcpTest() {
}

TcpSession *OvsdbClientTcpTest::AllocSession(Socket *socket) {
    TcpSession *session = new OvsdbClientTcpSessionTest(agent_, peer_manager_,
                                                        this, socket);
    session->set_observer(boost::bind(&OvsdbClientTcp::OnSessionEvent,
                                      this, _1, _2));
    return session;
}

void OvsdbClientTcpTest::Connect(TcpSession *session, Endpoint remote) {
    if (enable_connect_) {
        OvsdbClientTcp::Connect(session, remote);
    }
}

void OvsdbClientTcpTest::set_enable_connect(bool enable) {
    if (enable_connect_ != enable) {
        enable_connect_ = enable;
        if (enable_connect_) {
            Connect(session_, server_ep_);
        }
    }
}

TestOvsAgentInit::TestOvsAgentInit() : TestAgentInit() {
}

TestOvsAgentInit::~TestOvsAgentInit() {
}

/****************************************************************************
 * Initialization routines
 ***************************************************************************/
// Create the basic modules for agent operation.
// Optional modules or modules that have different implementation are created
// by init module
void TestOvsAgentInit::CreateModules() {
    TestAgentInit::CreateModules();
    if (ovs_init_) {
        start_ovsdb_server();
        ovsdb_client_.reset(new OVSDB::OvsdbClientTcpTest(agent(),
                    IpAddress(Ip4Address::from_string("127.0.0.1")), ovsdb_port,
                    IpAddress(Ip4Address::from_string("127.0.0.1")), 0,
                    ovs_peer_manager()));
        agent()->set_ovsdb_client(ovsdb_client_.get());
    }
}

void TestOvsAgentInit::CreateDBTables() {
    TestAgentInit::CreateDBTables();
}

void TestOvsAgentInit::RegisterDBClients() {
    TestAgentInit::RegisterDBClients();
    if (ovs_init_)
        ovsdb_client_->RegisterClients();
}

void TestOvsAgentInit::CreatePeers() {
    ovs_peer_manager_.reset(new OvsPeerManager(agent()));
}

/****************************************************************************
 * Access routines
 ****************************************************************************/
OvsPeerManager *TestOvsAgentInit::ovs_peer_manager() const {
    return ovs_peer_manager_.get();
}

OVSDB::OvsdbClientTcp *TestOvsAgentInit::ovsdb_client() const {
    return ovsdb_client_.get();
}

void TestOvsAgentInit::set_ovs_init(bool ovs_init) {
    ovs_init_ = ovs_init;
}

void TestOvsAgentInit::KSyncShutdown() {
    if (ovsdb_client_.get())
        ovsdb_client_->shutdown();
}

void LoadAndRun(const std::string &file_name) {
    AgentUtXmlTest test(file_name);
    AgentUtXmlOperInit(&test);
    AgentUtXmlPhysicalDeviceInit(&test);
    AgentUtXmlOvsdbInit(&test);
    if (test.Load() == true) {
        test.ReadXml();
        string str;
        test.ToString(&str);
        cout << str << endl;
        test.Run();
    }
}

bool LoadXml(AgentUtXmlTest &test) {
    AgentUtXmlOperInit(&test);
    AgentUtXmlPhysicalDeviceInit(&test);
    AgentUtXmlOvsdbInit(&test);
    if (test.Load() == true) {
        test.ReadXml();
        string str;
        test.ToString(&str);
        cout << str << endl;
        return true;
    }
    return false;
}

TestClient *OvsTestInit(const char *init_file, bool ovs_init) {
    TestClient *client = new TestClient(new TestOvsAgentInit());
    TestOvsAgentInit *init =
        static_cast<TestOvsAgentInit *>(client->agent_init());
    Agent *agent = client->agent();

    AgentParam *param = client->param();
    init->set_agent_param(param);
    // Read agent parameters from config file and arguments
    init->ProcessOptions(init_file, "test");
    param->set_agent_stats_interval(AgentParam::kAgentStatsInterval);
    param->set_flow_stats_interval(AgentParam::kFlowStatsInterval);
    param->set_vrouter_stats_interval(AgentParam::kVrouterStatsInterval);

    // Initialize the agent-init control class
    int introspect_port = 0;
    Sandesh::InitGeneratorTest("VNSWAgent", "Agent", "Test", "Test",
                               agent->event_manager(), introspect_port, NULL);

    init->set_ksync_enable(false);
    init->set_packet_enable(false);
    init->set_services_enable(false);
    init->set_create_vhost(false);
    init->set_uve_enable(true);
    init->set_vgw_enable(false);
    init->set_router_id_dep_enable(false);
    init->set_ovs_init(ovs_init);
    param->set_test_mode(true);
    agent->set_ksync_sync_mode(true);

    // Initialize agent and kick start initialization
    init->Start();
    WaitForInitDone(agent);

    client->Init();
    client->WaitForIdle();
    client->SetFlowFlushExclusionPolicy();
    client->SetFlowAgeExclusionPolicy();

    AsioRun();

    return client;
}
<commit_msg>Fix OVSDB UT coverage build<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <csetjmp>

#include <base/os.h>
#include <base/test/task_test_util.h>

#include <cmn/agent_cmn.h>
#include <cmn/agent_factory.h>
#include <init/agent_param.h>
#include <cfg/cfg_init.h>
#include <ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h>

#include <oper/operdb_init.h>
#include <vrouter/ksync/ksync_init.h>
#include <vrouter/ksync/test/ksync_test.h>
#include <uve/agent_uve.h>
#include <uve/test/agent_uve_test.h>
#include "test/test_init.h"
#include <test/test_agent_init.h>
#include "test_ovs_agent_init.h"
#include "test-xml/test_xml_oper.h"
#include "test_xml_physical_device.h"
#include "test_xml_ovsdb.h"

#include <boost/filesystem/operations.hpp>

#define OVSDB_SERVER "build/third_party/openvswitch/ovsdb/ovsdb-server"
#define DB_FILE_TEMPLATE "controller/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/vtep.db"

using namespace OVSDB;
std::string db_file_name;
std::string lock_file_name;
bool server_inited = false;
bool server_stopping = false;
int server_pid;
jmp_buf env;
uint32_t ovsdb_port = 0;

void stop_ovsdb_server() {
    if (server_inited == false || server_stopping == true) {
        return;
    }
    server_stopping = true;
    kill(server_pid, SIGTERM);
    int status;
    while (server_pid != wait(&status));
    // after the child process has exited, delete the db file and lock file
    boost::filesystem::remove(db_file_name);
    boost::filesystem::remove(lock_file_name);
    server_inited = false;
    server_stopping = false;
}

void signalHandler(int sig_num) {
    stop_ovsdb_server();
    longjmp (env, 1);
}

static void start_ovsdb_server() {
    assert(server_inited == false);
    signal(SIGABRT, signalHandler);
    signal(SIGSEGV, signalHandler);
    signal(SIGTERM, signalHandler);
    atexit(stop_ovsdb_server);
    server_inited = true;
    db_file_name =
        "build/vtep_" + boost::lexical_cast<std::string>(getpid()) + "_" +
        boost::lexical_cast<std::string>(UTCTimestampUsec()) + ".db";
    lock_file_name = db_file_name;
    size_t pos = lock_file_name.find("vtep_");
    lock_file_name.insert(pos, ".");
    lock_file_name.append(".~lock~");
    // create a new DB for Ovsdb Server from DB Template file
    boost::filesystem::copy_file(DB_FILE_TEMPLATE, db_file_name);
    server_pid = fork();

    if (server_pid == 0) {
        execlp(OVSDB_SERVER, OVSDB_SERVER, "--remote=ptcp:0:127.0.0.1",
               db_file_name.c_str(), static_cast<char *>(NULL));
    }

    std::string port = "";
    // Get the TCP server port used by ovsdb-server.
    int count = 0;
    do {
        usleep(1000);
        assert(count < 10000);
        count++;
        std::string cmd("netstat -anp | grep tcp | grep ");
        cmd += boost::lexical_cast<std::string>(server_pid);
        cmd += "/ovsdb-server";
        FILE* pipe = popen(cmd.c_str(), "r");
        if (!pipe) assert(false);
        char buffer[128];
        std::string result;
        while(!feof(pipe)) {
            if(fgets(buffer, 128, pipe) != NULL)
                result += buffer;
        }
        pclose(pipe);
        size_t start = result.find("127.0.0.1:");
        // find will fail if the process has not started the listen on socket
        if (start == string::npos)
            continue;
        start += 10;
        size_t end = result.find_first_of(' ', start);
        assert(end != string::npos);
        port = result.substr(start, end - start);
    } while (port.empty());
    ovsdb_port = strtoul(port.c_str(), NULL, 0);
}

OvsdbClientTcpSessionTest::OvsdbClientTcpSessionTest(Agent *agent,
                                                     OvsPeerManager *manager,
                                                     TcpServer *server,
                                                     Socket *sock,
                                                     bool async_ready)
    : OvsdbClientTcpSession(agent, manager, server, sock, async_ready) {
}

OvsdbClientTcpSessionTest::~OvsdbClientTcpSessionTest() {
}

OvsdbClientTcpTest::OvsdbClientTcpTest(Agent *agent, IpAddress tor_ip,
                                       int tor_port, IpAddress tsn_ip,
                                       int keepalive, OvsPeerManager *manager)
    : OvsdbClientTcp(agent, tor_ip, tor_port, tsn_ip, keepalive, -1, manager),
    enable_connect_(true) {
}

OvsdbClientTcpTest::~OvsdbClientTcpTest() {
}

TcpSession *OvsdbClientTcpTest::AllocSession(Socket *socket) {
    TcpSession *session = new OvsdbClientTcpSessionTest(agent_, peer_manager_,
                                                        this, socket);
    session->set_observer(boost::bind(&OvsdbClientTcp::OnSessionEvent,
                                      this, _1, _2));
    return session;
}

void OvsdbClientTcpTest::Connect(TcpSession *session, Endpoint remote) {
    if (enable_connect_) {
        OvsdbClientTcp::Connect(session, remote);
    }
}

void OvsdbClientTcpTest::set_enable_connect(bool enable) {
    if (enable_connect_ != enable) {
        enable_connect_ = enable;
        if (enable_connect_) {
            Connect(session_, server_ep_);
        }
    }
}

TestOvsAgentInit::TestOvsAgentInit() : TestAgentInit() {
}

TestOvsAgentInit::~TestOvsAgentInit() {
}

/****************************************************************************
 * Initialization routines
 ***************************************************************************/
// Create the basic modules for agent operation.
// Optional modules or modules that have different implementation are created
// by init module
void TestOvsAgentInit::CreateModules() {
    TestAgentInit::CreateModules();
    if (ovs_init_) {
        start_ovsdb_server();
        ovsdb_client_.reset(new OVSDB::OvsdbClientTcpTest(agent(),
                    IpAddress(Ip4Address::from_string("127.0.0.1")), ovsdb_port,
                    IpAddress(Ip4Address::from_string("127.0.0.1")), 0,
                    ovs_peer_manager()));
        agent()->set_ovsdb_client(ovsdb_client_.get());
    }
}

void TestOvsAgentInit::CreateDBTables() {
    TestAgentInit::CreateDBTables();
}

void TestOvsAgentInit::RegisterDBClients() {
    TestAgentInit::RegisterDBClients();
    if (ovs_init_)
        ovsdb_client_->RegisterClients();
}

void TestOvsAgentInit::CreatePeers() {
    ovs_peer_manager_.reset(new OvsPeerManager(agent()));
}

/****************************************************************************
 * Access routines
 ****************************************************************************/
OvsPeerManager *TestOvsAgentInit::ovs_peer_manager() const {
    return ovs_peer_manager_.get();
}

OVSDB::OvsdbClientTcp *TestOvsAgentInit::ovsdb_client() const {
    return ovsdb_client_.get();
}

void TestOvsAgentInit::set_ovs_init(bool ovs_init) {
    ovs_init_ = ovs_init;
}

void TestOvsAgentInit::KSyncShutdown() {
    if (ovsdb_client_.get())
        ovsdb_client_->shutdown();
}

void LoadAndRun(const std::string &file_name) {
    AgentUtXmlTest test(file_name);
    AgentUtXmlOperInit(&test);
    AgentUtXmlPhysicalDeviceInit(&test);
    AgentUtXmlOvsdbInit(&test);
    if (test.Load() == true) {
        test.ReadXml();
        string str;
        test.ToString(&str);
        cout << str << endl;
        test.Run();
    }
}

bool LoadXml(AgentUtXmlTest &test) {
    AgentUtXmlOperInit(&test);
    AgentUtXmlPhysicalDeviceInit(&test);
    AgentUtXmlOvsdbInit(&test);
    if (test.Load() == true) {
        test.ReadXml();
        string str;
        test.ToString(&str);
        cout << str << endl;
        return true;
    }
    return false;
}

TestClient *OvsTestInit(const char *init_file, bool ovs_init) {
    TestClient *client = new TestClient(new TestOvsAgentInit());
    TestOvsAgentInit *init =
        static_cast<TestOvsAgentInit *>(client->agent_init());
    Agent *agent = client->agent();

    AgentParam *param = client->param();
    init->set_agent_param(param);
    // Read agent parameters from config file and arguments
    init->ProcessOptions(init_file, "test");
    param->set_agent_stats_interval(AgentParam::kAgentStatsInterval);
    param->set_flow_stats_interval(AgentParam::kFlowStatsInterval);
    param->set_vrouter_stats_interval(AgentParam::kVrouterStatsInterval);

    // Initialize the agent-init control class
    int introspect_port = 0;
    Sandesh::InitGeneratorTest("VNSWAgent", "Agent", "Test", "Test",
                               agent->event_manager(), introspect_port, NULL);

    init->set_ksync_enable(false);
    init->set_packet_enable(false);
    init->set_services_enable(false);
    init->set_create_vhost(false);
    init->set_uve_enable(true);
    init->set_vgw_enable(false);
    init->set_router_id_dep_enable(false);
    init->set_ovs_init(ovs_init);
    param->set_test_mode(true);
    agent->set_ksync_sync_mode(true);

    // Initialize agent and kick start initialization
    init->Start();
    WaitForInitDone(agent);

    client->Init();
    client->WaitForIdle();
    client->SetFlowFlushExclusionPolicy();
    client->SetFlowAgeExclusionPolicy();

    AsioRun();

    return client;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 "tools/trace_to_text/trace_to_json.h"

#include <stdio.h>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/temp_file.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "tools/trace_to_text/utils.h"

namespace perfetto {
namespace trace_to_text {

namespace {

const char kTraceHeader[] = R"({
  "traceEvents": [],
)";

const char kTraceFooter[] = R"(,
  "controllerTraceDataKey": "systraceController"
})";

bool ExportUserspaceEvents(trace_processor::TraceProcessor* tp,
                           TraceWriter* writer) {
  fprintf(stderr, "Converting userspace events%c", kProgressChar);
  fflush(stderr);

  // Write userspace trace to a temporary file.
  // TODO(eseckler): Support streaming the result out of TP directly instead.
  auto file = base::TempFile::Create();
  char query[100];
  sprintf(query, "select export_json(\"%s\")", file.path().c_str());
  auto it = tp->ExecuteQuery(query);

  if (!it.Next()) {
    auto status = it.Status();
    PERFETTO_CHECK(!status.ok());
    PERFETTO_ELOG("Could not convert userspace events: %s", status.c_message());
    return false;
  }

  base::ScopedFstream source(fopen(file.path().c_str(), "r"));
  if (!source) {
    PERFETTO_ELOG("Could not convert userspace events: Couldn't read file %s",
                  file.path().c_str());
    return false;
  }

  char buf[BUFSIZ];
  size_t size;
  while ((size = fread(buf, sizeof(char), BUFSIZ, *source)) > 0) {
    // Skip writing the closing brace since we'll append system trace data.
    if (feof(*source))
      size--;
    writer->Write(buf, size);
  }
  return true;
}

}  // namespace

int TraceToJson(std::istream* input,
                std::ostream* output,
                bool compress,
                Keep truncate_keep) {
  std::unique_ptr<TraceWriter> trace_writer(
      compress ? new DeflateTraceWriter(output) : new TraceWriter(output));

  trace_processor::Config config;
  std::unique_ptr<trace_processor::TraceProcessor> tp =
      trace_processor::TraceProcessor::CreateInstance(config);

  if (!ReadTrace(tp.get(), input))
    return 1;
  tp->NotifyEndOfFile();

  // TODO(eseckler): Support truncation of userspace event data.
  if (ExportUserspaceEvents(tp.get(), trace_writer.get())) {
    trace_writer->Write(",\n");
  } else {
    trace_writer->Write(kTraceHeader);
  }

  int ret = ExtractSystrace(tp.get(), trace_writer.get(),
                            /*wrapped_in_json=*/true, truncate_keep);
  if (ret)
    return ret;

  trace_writer->Write(kTraceFooter);
  return 0;
}

}  // namespace trace_to_text
}  // namespace perfetto
<commit_msg>traceconv: ignore userspace events for traces with Android data<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 "tools/trace_to_text/trace_to_json.h"

#include <stdio.h>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/temp_file.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "tools/trace_to_text/utils.h"

namespace perfetto {
namespace trace_to_text {

namespace {

const char kTraceHeader[] = R"({
  "traceEvents": [],
)";

const char kTraceFooter[] = R"(,
  "controllerTraceDataKey": "systraceController"
})";

bool ExportUserspaceEvents(trace_processor::TraceProcessor* tp,
                           TraceWriter* writer) {
  // First check if there are any non-Chrome events. If so then bail out.
  // TODO(eseckler): support merged Android/Chrome traces.
  static const char kSystemEventsQuery[] =
      "select count(1) from raw "
      "where name not like 'chrome.%' "
      "and name not like 'track_event.%'";
  auto raw_it = tp->ExecuteQuery(kSystemEventsQuery);
  if (!raw_it.Next()) {
    auto status = raw_it.Status();
    PERFETTO_ELOG("Failed when counting non-Chrome raw events %s.",
                  status.c_message());
    return false;
  }
  auto count_val = raw_it.Get(0);
  PERFETTO_CHECK(count_val.type == trace_processor::SqlValue::kLong);
  PERFETTO_DCHECK(!raw_it.Next());

  if (count_val.long_value > 0)
    return false;

  fprintf(stderr, "Converting userspace events%c", kProgressChar);
  fflush(stderr);

  // Write userspace trace to a temporary file.
  // TODO(eseckler): Support streaming the result out of TP directly instead.
  auto file = base::TempFile::Create();
  char query[100];
  sprintf(query, "select export_json(\"%s\")", file.path().c_str());
  auto it = tp->ExecuteQuery(query);

  if (!it.Next()) {
    auto status = it.Status();
    PERFETTO_CHECK(!status.ok());
    PERFETTO_ELOG("Could not convert userspace events: %s", status.c_message());
    return false;
  }

  base::ScopedFstream source(fopen(file.path().c_str(), "r"));
  if (!source) {
    PERFETTO_ELOG("Could not convert userspace events: Couldn't read file %s",
                  file.path().c_str());
    return false;
  }

  char buf[BUFSIZ];
  size_t size;
  while ((size = fread(buf, sizeof(char), BUFSIZ, *source)) > 0) {
    // Skip writing the closing brace since we'll append system trace data.
    if (feof(*source))
      size--;
    writer->Write(buf, size);
  }
  return true;
}

}  // namespace

int TraceToJson(std::istream* input,
                std::ostream* output,
                bool compress,
                Keep truncate_keep) {
  std::unique_ptr<TraceWriter> trace_writer(
      compress ? new DeflateTraceWriter(output) : new TraceWriter(output));

  trace_processor::Config config;
  std::unique_ptr<trace_processor::TraceProcessor> tp =
      trace_processor::TraceProcessor::CreateInstance(config);

  if (!ReadTrace(tp.get(), input))
    return 1;
  tp->NotifyEndOfFile();

  // TODO(eseckler): Support truncation of userspace event data.
  if (ExportUserspaceEvents(tp.get(), trace_writer.get())) {
    trace_writer->Write(",\n");
  } else {
    trace_writer->Write(kTraceHeader);
  }

  int ret = ExtractSystrace(tp.get(), trace_writer.get(),
                            /*wrapped_in_json=*/true, truncate_keep);
  if (ret)
    return ret;

  trace_writer->Write(kTraceFooter);
  return 0;
}

}  // namespace trace_to_text
}  // namespace perfetto
<|endoftext|>


<commit_before>#ifdef _WIN32
#define M_PI 3.14
#endif

#include <cmath>
#include <iostream>
#include <fstream>

#include "Body.hpp"

#define G 20 // TODO: Get the right number
#define DENSITY 100 // kg/m^3

using namespace sf;
using namespace std;

Body::Body(Vector2f pos, uint64_t m, Vector2f dir)
	: position(pos), direction(dir), mass(m)
{
	if (mass <= 0)
	{
		cout << "FATAL ERROR: MASS <= 0" << endl;
	}

	cout << "MASS=" << mass << endl;

	// Radius
	float volume = mass / DENSITY;
	radius = cbrt((3*volume)/(4*M_PI));

	if (radius < 1)
	{
		radius = 1;
	}

	Color color(Color::White);
	Color clear_yellow(212, 193, 106);
	Color brown(175, 75, 0);

	if (mass <= 10000)
	{
		color = interpolate(Color::White, clear_yellow, mass / 10000.0f);
	}
	else if (mass <= 100000)
	{
		color = interpolate(clear_yellow, brown, mass / 100000.0f);
	}
	else if (mass >= 1000000)
	{
		color = Color::Red;
	}
	else
	{
		color = interpolate(brown, Color::Red, mass  / 1000000.0f);
	}

	shape.setRadius(radius);
	shape.setFillColor(color);
}

void Body::move(float dt)
{
	position += direction * dt;
}

void Body::applyGravityOf(const Body &b, float dt)
{
	float r = getDistanceTo(b);

	if (r <= 0)
	{
		cout << "return" << endl;
		return;
	}

	float F = (G*mass*b.mass) / (r*r);

	// Make the force proportional to the mass
	F /= mass;

	// Get the unit vector to the other body
	Vector2f target(b.position.x+b.radius, b.position.y+b.radius);
	Vector2f center(position.x+radius, position.y+radius);
	Vector2f to_Body(target - center);
	to_Body = to_Body / r;

	// Apply the force in the direction of the other body
	direction += (to_Body * F) * dt;
}

float Body::getDistanceTo(const Body &b)
{
	Vector2f target(b.position.x+b.radius, b.position.y+b.radius);
	Vector2f center(position.x+radius, position.y+radius);
	Vector2f c = target - center;

	return sqrt(c.x*c.x + c.y * c.y);
}

void Body::draw(RenderWindow &window)
{
	shape.setPosition(position);
	window.draw(shape);
}

bool Body::collideWith(const Body &p)
{
	Vector2f a = position;
	a.x += radius;
	a.y += radius;

	Vector2f b = p.position;
	b.x += p.radius;
	b.y += p.radius;

	float d = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);

	if (d <= (radius+p.radius)*(radius+p.radius))
		return true;
	return false;
}

bool Body::contains(const Vector2f &point)
{
	Vector2f center(position.x+radius, position.y+radius);
	return (point.x-center.x)*(point.x-center.x)
		 + (point.y-center.y)*(point.y-center.y) <= radius*radius;
}

// Handy helper fonctions

/*
 *	ratio is a number between 0.0f and 1.0f
 */
Color interpolate(Color a, Color b, float ratio)
{
	Color c;
	c.r = (b.r-a.r) * ratio + a.r;
	c.g = (b.g-a.g) * ratio + a.g;
	c.b = (b.b-a.b) * ratio + a.b;

	return c;
}
<commit_msg>Delete Body.cpp<commit_after><|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://users.dune-project.org/projects/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_FLOAT_CMP_HH
#define DUNE_STUFF_COMMON_FLOAT_CMP_HH

#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/float_cmp.hh>
#include <dune/stuff/common/reenable_warnings.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/fvector.hh>

#if HAVE_EIGEN
# include <dune/stuff/la/container/eigen.hh>
#endif

#include <type_traits>

namespace Dune {
namespace Stuff {
namespace Common {
namespace FloatCmp {

#define DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(id) \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  typename std::enable_if< std::is_arithmetic< T >::value, bool >::type \
    id (const T& first, \
        const T& second, \
        typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    return Dune::FloatCmp:: id < T, style >(first, second, epsilon); \
  } \
 \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  typename std::enable_if< std::is_arithmetic< T >::value, bool >::type \
    id (const std::vector< T >& first, \
        const std::vector< T >& second, \
        typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    assert(first.size() == second.size()); \
    for (size_t ii = 0; ii < first.size(); ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
      return true; \
  } \
 \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  bool id (const Dune::DynamicVector< T >& first, \
           const Dune::DynamicVector< T >& second, \
           typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    assert(first.size() == second.size()); \
    for (size_t ii = 0; ii < first.size(); ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
      return true; \
  } \
 \
  template< class T, int size, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  bool id (const Dune::FieldVector< T, size >& first, \
           const Dune::FieldVector< T, size >& second, \
           typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    for (size_t ii = 0; ii < size; ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
    return true; \
  }
// DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(eq)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ne)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(gt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(lt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ge)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(le)

#undef DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

#if HAVE_EIGEN

#define DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(id) \
template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
bool id (const Dune::Stuff::LA::EigenDenseVector< T >& first, \
         const Dune::Stuff::LA::EigenDenseVector< T >& second, \
         typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
{ \
  assert(first.size() == second.size()); \
  for (size_t ii = 0; ii < first.size(); ++ii) \
    if (!Dune::FloatCmp:: id < T, style >(first.backend()[ii], second.backend()[ii], epsilon)) \
      return false; \
    return true; \
} \
 \
template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
bool id (const Dune::DynamicVector< T >& first, \
         const Dune::Stuff::LA::EigenDenseVector< T >& second, \
         typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
{ \
  assert(first.size() == second.size()); \
  for (size_t ii = 0; ii < first.size(); ++ii) \
    if (!Dune::FloatCmp:: id < T, style >(first[ii], second.backend()[ii], epsilon)) \
      return false; \
    return true; \
} \
 \
template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
bool id (const Dune::Stuff::LA::EigenDenseVector< T >& first, \
         const Dune::DynamicVector< T >& second, \
         typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
{ \
  assert(first.size() == second.size()); \
  for (size_t ii = 0; ii < first.size(); ++ii) \
    if (!Dune::FloatCmp:: id< T, style >(first[ii], second.backend()[ii], epsilon)) \
      return false; \
    return true; \
}
// DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(eq)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ne)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(gt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(lt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ge)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(le)

#undef DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

#endif // HAVE_EIGEN

} // namespace FloatCmp
} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_FLOAT_CMP_HH
<commit_msg>[common.float_cmp] allow comparison of LA::VectorInterface vectors<commit_after>// This file is part of the dune-stuff project:
//   https://users.dune-project.org/projects/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_FLOAT_CMP_HH
#define DUNE_STUFF_COMMON_FLOAT_CMP_HH

#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/float_cmp.hh>
#include <dune/stuff/common/reenable_warnings.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/fvector.hh>

#include <dune/stuff/la/container/interfaces.hh>

#include <type_traits>

namespace Dune {
namespace Stuff {
namespace Common {
namespace FloatCmp {

#define DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(id) \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  typename std::enable_if< std::is_arithmetic< T >::value, bool >::type \
    id (const T& first, \
        const T& second, \
        typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    return Dune::FloatCmp:: id < T, style >(first, second, epsilon); \
  } \
 \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  typename std::enable_if< std::is_arithmetic< T >::value, bool >::type \
    id (const std::vector< T >& first, \
        const std::vector< T >& second, \
        typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    assert(first.size() == second.size()); \
    for (size_t ii = 0; ii < first.size(); ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
      return true; \
  } \
 \
  template< class T, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  bool id (const Dune::DynamicVector< T >& first, \
           const Dune::DynamicVector< T >& second, \
           typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    assert(first.size() == second.size()); \
    for (size_t ii = 0; ii < first.size(); ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
      return true; \
  } \
 \
  template< class T, int size, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  bool id (const Dune::FieldVector< T, size >& first, \
           const Dune::FieldVector< T, size >& second, \
           typename Dune::FloatCmp::EpsilonType< T >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< T, style >::value()) \
  { \
    for (size_t ii = 0; ii < size; ++ii) \
      if (!Dune::FloatCmp:: id < T, style >(first[ii], second[ii], epsilon)) \
        return false; \
    return true; \
  } \
  template< class F, class S, Dune::FloatCmp::CmpStyle style = Dune::FloatCmp::defaultCmpStyle > \
  bool id (const Stuff::LA::VectorInterface< F >& first, \
           const Stuff::LA::VectorInterface< S >& second, \
           typename Dune::FloatCmp::EpsilonType< typename F::ScalarType >::Type epsilon = Dune::FloatCmp::DefaultEpsilon< typename F::ScalarType, style >::value()) \
  { \
    assert(first.size() == second.size()); \
    for (size_t ii = 0; ii < first.size(); ++ii) \
      if (!Dune::FloatCmp:: id < typename F::ScalarType, style >(first[ii], second[ii], epsilon)) \
        return false; \
    return true; \
  }
// DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(eq)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ne)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(gt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(lt)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(ge)
DUNE_STUFF_GENERATE_VECTOR_COMPARATOR(le)

#undef DUNE_STUFF_GENERATE_VECTOR_COMPARATOR

} // namespace FloatCmp
} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_FLOAT_CMP_HH
<|endoftext|>


<commit_before>#include "map/framework.hpp"
#include "map/user_mark_container.hpp"

#include "drape_frontend/drape_engine.hpp"
#include "drape_frontend/tile_key.hpp"
#include "drape_frontend/user_mark_shapes.hpp"

#include "base/scope_guard.hpp"
#include "base/macros.hpp"
#include "base/stl_add.hpp"

#include "std/algorithm.hpp"

////////////////////////////////////////////////////////////////////////

namespace
{
  class FindMarkFunctor
  {
  public:
    FindMarkFunctor(UserMark ** mark, double & minD, m2::AnyRectD const & rect)
      : m_mark(mark)
      , m_minD(minD)
      , m_rect(rect)
    {
      m_globalCenter = rect.GlobalCenter();
    }

    void operator()(UserMark * mark)
    {
      m2::PointD const & org = mark->GetPivot();
      if (m_rect.IsPointInside(org))
      {
        double minDCandidate = m_globalCenter.SquareLength(org);
        if (minDCandidate < m_minD)
        {
          *m_mark = mark;
          m_minD = minDCandidate;
        }
      }
    }

    UserMark ** m_mark;
    double & m_minD;
    m2::AnyRectD const & m_rect;
    m2::PointD m_globalCenter;
  };

  df::TileKey CreateTileKey(UserMarkContainer const * cont)
  {
    switch (cont->GetType())
    {
    case UserMarkType::API_MARK:
      return df::GetApiTileKey();
    case UserMarkType::SEARCH_MARK:
      return df::GetSearchTileKey();
    case UserMarkType::BOOKMARK_MARK:
      return df::GetBookmarkTileKey(reinterpret_cast<size_t>(cont));
    case UserMarkType::DEBUG_MARK:
      return df::GetDebugTileKey();
    default:
      ASSERT(false, ());
      break;
    }

    return df::TileKey();
  }

  size_t const VisibleFlag = 0;
  size_t const VisibleDirtyFlag = 1;
  size_t const DrawableFlag = 2;
  size_t const DrawableDirtyFlag = 3;
}

UserMarkContainer::UserMarkContainer(double layerDepth, UserMarkType type, Framework & fm)
  : m_framework(fm)
  , m_layerDepth(layerDepth)
  , m_type(type)
{
  m_flags.set();
}

UserMarkContainer::~UserMarkContainer()
{
  RequestController().Clear();
  ReleaseController();
}

UserMark const * UserMarkContainer::FindMarkInRect(m2::AnyRectD const & rect, double & d) const
{
  UserMark * mark = nullptr;
  if (IsVisible())
  {
    FindMarkFunctor f(&mark, d, rect);
    for (size_t i = 0; i < m_userMarks.size(); ++i)
    {
      if (rect.IsPointInside(m_userMarks[i]->GetPivot()))
         f(m_userMarks[i].get());
    }
  }
  return mark;
}

namespace
{
unique_ptr<PoiMarkPoint> g_selectionUserMark;
unique_ptr<MyPositionMarkPoint> g_myPosition;
}

UserMarkDLCache::Key UserMarkContainer::GetDefaultKey() const
{
  return UserMarkDLCache::Key(GetTypeName(), graphics::EPosCenter, GetDepth());
}

void UserMarkContainer::InitStaticMarks(UserMarkContainer * container)
{
  if (g_selectionUserMark == NULL)
    g_selectionUserMark.reset(new PoiMarkPoint(container));

  if (g_myPosition == NULL)
    g_myPosition.reset(new MyPositionMarkPoint(container));
}

PoiMarkPoint * UserMarkContainer::UserMarkForPoi()
{
  ASSERT(g_selectionUserMark != NULL, ());
  return g_selectionUserMark.get();
}

MyPositionMarkPoint * UserMarkContainer::UserMarkForMyPostion()
{
  ASSERT(g_myPosition != NULL, ());
  return g_myPosition.get();
}

UserMarksController & UserMarkContainer::RequestController()
{
  BeginWrite();
  return *this;
}

void UserMarkContainer::ReleaseController()
{
  MY_SCOPE_GUARD(endWriteGuard, [this]{ EndWrite(); });
  ref_ptr<df::DrapeEngine> engine = m_framework.GetDrapeEngine();
  if (engine == nullptr)
    return;

  df::TileKey key = CreateTileKey(this);
  if (IsVisibleFlagDirty() || IsDrawableFlagDirty())
    engine->ChangeVisibilityUserMarksLayer(key, IsVisible() && IsDrawable());

  m_flags[VisibleDirtyFlag] = false;
  m_flags[DrawableDirtyFlag] = false;

  if (IsDirty())
  {
    if (GetUserPointCount() == 0 && GetUserLineCount() == 0)
      engine->ClearUserMarksLayer(key);
    else
      engine->UpdateUserMarksLayer(key, this);
  }
}

size_t UserMarkContainer::GetUserPointCount() const
{
  return m_userMarks.size();
}

df::UserPointMark const * UserMarkContainer::GetUserPointMark(size_t index) const
{
  return GetUserMark(index);
}

size_t UserMarkContainer::GetUserLineCount() const
{
  return 0;
}

df::UserLineMark const * UserMarkContainer::GetUserLineMark(size_t index) const
{
  UNUSED_VALUE(index);
  ASSERT(false, ());
  return nullptr;
}

float UserMarkContainer::GetPointDepth() const
{
  return m_layerDepth;
}

bool UserMarkContainer::IsVisible() const
{
  return m_flags[VisibleFlag];
}

bool UserMarkContainer::IsDrawable() const
{
  return m_flags[DrawableFlag];
}

UserMark * UserMarkContainer::CreateUserMark(m2::PointD const & ptOrg)
{
  SetDirty();
  m_userMarks.push_back(unique_ptr<UserMark>(AllocateUserMark(ptOrg)));
  return m_userMarks.back().get();
}

size_t UserMarkContainer::GetUserMarkCount() const
{
  return GetUserPointCount();
}

UserMark const * UserMarkContainer::GetUserMark(size_t index) const
{
  ASSERT_LESS(index, m_userMarks.size(), ());
  return m_userMarks[index].get();
}

UserMarkType UserMarkContainer::GetType() const
{
  return m_type;
}

UserMark * UserMarkContainer::GetUserMarkForEdit(size_t index)
{
  SetDirty();
  ASSERT_LESS(index, m_userMarks.size(), ());
  return m_userMarks[index].get();
}

void UserMarkContainer::Clear(size_t skipCount/* = 0*/)
{
  SetDirty();
  if (skipCount < m_userMarks.size())
    m_userMarks.erase(m_userMarks.begin() + skipCount, m_userMarks.end());
}

void UserMarkContainer::SetIsDrawable(bool isDrawable)
{
  if (IsDrawable() != isDrawable)
  {
    m_flags[DrawableDirtyFlag] = true;
    m_flags[DrawableFlag] = isDrawable;
  }
}

void UserMarkContainer::SetIsVisible(bool isVisible)
{
  if (IsVisible() != isVisible)
  {
    m_flags[VisibleDirtyFlag] = true;
    m_flags[VisibleFlag] = isVisible;
  }
}

bool UserMarkContainer::IsVisibleFlagDirty()
{
  return m_flags[VisibleDirtyFlag];
}

bool UserMarkContainer::IsDrawableFlagDirty()
{
  return m_flags[DrawableDirtyFlag];
}

namespace
{

template <class T> void DeleteItem(vector<T> & v, size_t i)
{
  if (i < v.size())
  {
    delete v[i];
    v.erase(v.begin() + i);
  }
  else
  {
    LOG(LWARNING, ("Trying to delete non-existing item at index", i));
  }
}

}

void UserMarkContainer::DeleteUserMark(size_t index)
{
  SetDirty();
  ASSERT_LESS(index, m_userMarks.size(), ());
  if (index < m_userMarks.size())
    m_userMarks.erase(m_userMarks.begin() + index);
  else
    LOG(LWARNING, ("Trying to delete non-existing item at index", index));
}

SearchUserMarkContainer::SearchUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::SEARCH_MARK, framework)
{
}

UserMark * SearchUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new SearchMarkPoint(ptOrg, this);
}

ApiUserMarkContainer::ApiUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::API_MARK, framework)
{
}

UserMark * ApiUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new ApiMarkPoint(ptOrg, this);
}

DebugUserMarkContainer::DebugUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::DEBUG_MARK, framework)
{
}

UserMark * DebugUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new DebugMarkPoint(ptOrg, this);
}
<commit_msg>Review fixes<commit_after>#include "map/framework.hpp"
#include "map/user_mark_container.hpp"

#include "drape_frontend/drape_engine.hpp"
#include "drape_frontend/tile_key.hpp"
#include "drape_frontend/user_mark_shapes.hpp"

#include "base/scope_guard.hpp"
#include "base/macros.hpp"
#include "base/stl_add.hpp"

#include "std/algorithm.hpp"

////////////////////////////////////////////////////////////////////////

namespace
{
  class FindMarkFunctor
  {
  public:
    FindMarkFunctor(UserMark ** mark, double & minD, m2::AnyRectD const & rect)
      : m_mark(mark)
      , m_minD(minD)
      , m_rect(rect)
    {
      m_globalCenter = rect.GlobalCenter();
    }

    void operator()(UserMark * mark)
    {
      m2::PointD const & org = mark->GetPivot();
      if (m_rect.IsPointInside(org))
      {
        double minDCandidate = m_globalCenter.SquareLength(org);
        if (minDCandidate < m_minD)
        {
          *m_mark = mark;
          m_minD = minDCandidate;
        }
      }
    }

    UserMark ** m_mark;
    double & m_minD;
    m2::AnyRectD const & m_rect;
    m2::PointD m_globalCenter;
  };

  df::TileKey CreateTileKey(UserMarkContainer const * cont)
  {
    switch (cont->GetType())
    {
    case UserMarkType::API_MARK:
      return df::GetApiTileKey();
    case UserMarkType::SEARCH_MARK:
      return df::GetSearchTileKey();
    case UserMarkType::BOOKMARK_MARK:
      return df::GetBookmarkTileKey(reinterpret_cast<size_t>(cont));
    case UserMarkType::DEBUG_MARK:
      return df::GetDebugTileKey();
    }

    ASSERT(false, ());
    return df::TileKey();
  }

  size_t const VisibleFlag = 0;
  size_t const VisibleDirtyFlag = 1;
  size_t const DrawableFlag = 2;
  size_t const DrawableDirtyFlag = 3;
}

UserMarkContainer::UserMarkContainer(double layerDepth, UserMarkType type, Framework & fm)
  : m_framework(fm)
  , m_layerDepth(layerDepth)
  , m_type(type)
{
  m_flags.set();
}

UserMarkContainer::~UserMarkContainer()
{
  RequestController().Clear();
  ReleaseController();
}

UserMark const * UserMarkContainer::FindMarkInRect(m2::AnyRectD const & rect, double & d) const
{
  UserMark * mark = nullptr;
  if (IsVisible())
  {
    FindMarkFunctor f(&mark, d, rect);
    for (size_t i = 0; i < m_userMarks.size(); ++i)
    {
      if (rect.IsPointInside(m_userMarks[i]->GetPivot()))
         f(m_userMarks[i].get());
    }
  }
  return mark;
}

namespace
{
unique_ptr<PoiMarkPoint> g_selectionUserMark;
unique_ptr<MyPositionMarkPoint> g_myPosition;
}

UserMarkDLCache::Key UserMarkContainer::GetDefaultKey() const
{
  return UserMarkDLCache::Key(GetTypeName(), graphics::EPosCenter, GetDepth());
}

void UserMarkContainer::InitStaticMarks(UserMarkContainer * container)
{
  if (g_selectionUserMark == NULL)
    g_selectionUserMark.reset(new PoiMarkPoint(container));

  if (g_myPosition == NULL)
    g_myPosition.reset(new MyPositionMarkPoint(container));
}

PoiMarkPoint * UserMarkContainer::UserMarkForPoi()
{
  ASSERT(g_selectionUserMark != NULL, ());
  return g_selectionUserMark.get();
}

MyPositionMarkPoint * UserMarkContainer::UserMarkForMyPostion()
{
  ASSERT(g_myPosition != NULL, ());
  return g_myPosition.get();
}

UserMarksController & UserMarkContainer::RequestController()
{
  BeginWrite();
  return *this;
}

void UserMarkContainer::ReleaseController()
{
  MY_SCOPE_GUARD(endWriteGuard, [this]{ EndWrite(); });
  ref_ptr<df::DrapeEngine> engine = m_framework.GetDrapeEngine();
  if (engine == nullptr)
    return;

  df::TileKey key = CreateTileKey(this);
  if (IsVisibleFlagDirty() || IsDrawableFlagDirty())
    engine->ChangeVisibilityUserMarksLayer(key, IsVisible() && IsDrawable());

  m_flags[VisibleDirtyFlag] = false;
  m_flags[DrawableDirtyFlag] = false;

  if (IsDirty())
  {
    if (GetUserPointCount() == 0 && GetUserLineCount() == 0)
      engine->ClearUserMarksLayer(key);
    else
      engine->UpdateUserMarksLayer(key, this);
  }
}

size_t UserMarkContainer::GetUserPointCount() const
{
  return m_userMarks.size();
}

df::UserPointMark const * UserMarkContainer::GetUserPointMark(size_t index) const
{
  return GetUserMark(index);
}

size_t UserMarkContainer::GetUserLineCount() const
{
  return 0;
}

df::UserLineMark const * UserMarkContainer::GetUserLineMark(size_t index) const
{
  UNUSED_VALUE(index);
  ASSERT(false, ());
  return nullptr;
}

float UserMarkContainer::GetPointDepth() const
{
  return m_layerDepth;
}

bool UserMarkContainer::IsVisible() const
{
  return m_flags[VisibleFlag];
}

bool UserMarkContainer::IsDrawable() const
{
  return m_flags[DrawableFlag];
}

UserMark * UserMarkContainer::CreateUserMark(m2::PointD const & ptOrg)
{
  SetDirty();
  m_userMarks.push_back(unique_ptr<UserMark>(AllocateUserMark(ptOrg)));
  return m_userMarks.back().get();
}

size_t UserMarkContainer::GetUserMarkCount() const
{
  return GetUserPointCount();
}

UserMark const * UserMarkContainer::GetUserMark(size_t index) const
{
  ASSERT_LESS(index, m_userMarks.size(), ());
  return m_userMarks[index].get();
}

UserMarkType UserMarkContainer::GetType() const
{
  return m_type;
}

UserMark * UserMarkContainer::GetUserMarkForEdit(size_t index)
{
  SetDirty();
  ASSERT_LESS(index, m_userMarks.size(), ());
  return m_userMarks[index].get();
}

void UserMarkContainer::Clear(size_t skipCount/* = 0*/)
{
  SetDirty();
  if (skipCount < m_userMarks.size())
    m_userMarks.erase(m_userMarks.begin() + skipCount, m_userMarks.end());
}

void UserMarkContainer::SetIsDrawable(bool isDrawable)
{
  if (IsDrawable() != isDrawable)
  {
    m_flags[DrawableDirtyFlag] = true;
    m_flags[DrawableFlag] = isDrawable;
  }
}

void UserMarkContainer::SetIsVisible(bool isVisible)
{
  if (IsVisible() != isVisible)
  {
    m_flags[VisibleDirtyFlag] = true;
    m_flags[VisibleFlag] = isVisible;
  }
}

bool UserMarkContainer::IsVisibleFlagDirty()
{
  return m_flags[VisibleDirtyFlag];
}

bool UserMarkContainer::IsDrawableFlagDirty()
{
  return m_flags[DrawableDirtyFlag];
}

namespace
{

template <class T> void DeleteItem(vector<T> & v, size_t i)
{
  if (i < v.size())
  {
    delete v[i];
    v.erase(v.begin() + i);
  }
  else
  {
    LOG(LWARNING, ("Trying to delete non-existing item at index", i));
  }
}

}

void UserMarkContainer::DeleteUserMark(size_t index)
{
  SetDirty();
  ASSERT_LESS(index, m_userMarks.size(), ());
  if (index < m_userMarks.size())
    m_userMarks.erase(m_userMarks.begin() + index);
  else
    LOG(LWARNING, ("Trying to delete non-existing item at index", index));
}

SearchUserMarkContainer::SearchUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::SEARCH_MARK, framework)
{
}

UserMark * SearchUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new SearchMarkPoint(ptOrg, this);
}

ApiUserMarkContainer::ApiUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::API_MARK, framework)
{
}

UserMark * ApiUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new ApiMarkPoint(ptOrg, this);
}

DebugUserMarkContainer::DebugUserMarkContainer(double layerDepth, Framework & framework)
  : UserMarkContainer(layerDepth, UserMarkType::DEBUG_MARK, framework)
{
}

UserMark * DebugUserMarkContainer::AllocateUserMark(const m2::PointD & ptOrg)
{
  return new DebugMarkPoint(ptOrg, this);
}
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          frame.cpp
* Purpose:       Implementation of wxExFrameWithHistory class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/tokenzr.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/frd.h>
#include <wx/extension/log.h>
#include <wx/extension/util.h>
#include <wx/extension/report/frame.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/dir.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listviewfile.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/stc.h>
#include <wx/extension/report/util.h>

// The maximal number of files and projects to be supported.
const int NUMBER_RECENT_FILES = 25;
const int NUMBER_RECENT_PROJECTS = 25;
const int ID_RECENT_PROJECT_LOWEST =  wxID_FILE1 + NUMBER_RECENT_FILES + 1;

BEGIN_EVENT_TABLE(wxExFrameWithHistory, wxExManagedFrame)
  EVT_CLOSE(wxExFrameWithHistory::OnClose)
  EVT_IDLE(wxExFrameWithHistory::OnIdle)
  EVT_MENU(wxID_OPEN, wxExFrameWithHistory::OnCommand)
  EVT_MENU(ID_TERMINATED_PROCESS, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    wxID_FILE1,
    wxID_FILE1 + NUMBER_RECENT_FILES, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    ID_RECENT_PROJECT_LOWEST,
    ID_RECENT_PROJECT_LOWEST + NUMBER_RECENT_PROJECTS, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    ID_EXTENSION_REPORT_LOWEST,
    ID_EXTENSION_REPORT_HIGHEST,
    wxExFrameWithHistory::OnCommand)
END_EVENT_TABLE()

wxExFrameWithHistory::wxExFrameWithHistory(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  size_t maxFiles,
  size_t maxProjects,
  int style)
  : wxExManagedFrame(parent, id, title, style)
  , m_FiFDialog(NULL)
  , m_TextInFiles(_("In files"))
  , m_TextInFolder(_("In folder"))
  , m_FileHistory(maxFiles, wxID_FILE1)
  , m_FileHistoryList(NULL)
  , m_ProjectHistory(maxProjects, ID_RECENT_PROJECT_LOWEST)
  , m_Process(NULL)
{
  // There is only support for one history in the config.
  // We use file history for this, so update project history ourselves.
  // The order should be inverted, as the last one added is the most recent used.
  for (int i = m_ProjectHistory.GetMaxFiles() - 1 ; i >=0 ; i--)
  {
    SetRecentProject(
      wxConfigBase::Get()->Read(wxString::Format("RecentProject%d", i)));
  }

#ifdef wxExUSE_EMBEDDED_SQL
  wxExTool::Get()->AddInfo(
    ID_TOOL_SQL,
    _("Executed %ld SQL queries in"),
    wxExEllipsed(_("&SQL Query Run")));

  wxExTool::Get()->AddInfo(
    ID_TOOL_REPORT_SQL,
    _("Reported %ld SQL queries in"),
    _("Report SQL &Query"));
#endif
}

wxExFrameWithHistory::~wxExFrameWithHistory()
{
  if (m_FiFDialog != NULL)
  {
    m_FiFDialog->Destroy();
  }
}

void wxExFrameWithHistory::DoRecent(
  wxFileHistory& history,
  int index,
  long flags)
{
  if (history.GetCount() > 0)
  {
    const wxString file(history.GetHistoryFile(index));

    if (!wxFileExists(file))
    {
      history.RemoveFileFromHistory(index);
      wxLogMessage(_("Removed not existing file: %s from history"),
        file.c_str());
    }
    else
    {
      OpenFile(file, 0, wxEmptyString, flags);
    }
  }
}

void wxExFrameWithHistory::FindInFiles(wxWindowID dialogid)
{
  const bool replace = (dialogid == ID_REPLACE_IN_FILES);
  const wxExTool tool =
    (replace ?
       ID_TOOL_REPORT_REPLACE:
       ID_TOOL_REPORT_FIND);

  if (!wxExTextFileWithListView::SetupTool(tool, this))
  {
    return;
  }

  wxExLog::Get()->Log(
    wxExFindReplaceData::Get()->GetFindReplaceInfoText(replace));

  wxExDirTool dir(
    tool,
    wxExConfigFirstOf(m_TextInFolder),
    wxExConfigFirstOf(m_TextInFiles));

  dir.FindFiles();

  tool.Log(
    &dir.GetStatistics().GetElements(),
    wxExConfigFirstOf(m_TextInFolder));
}

int wxExFrameWithHistory::FindInFilesDialog(int id)
{
  if (m_FiFDialog != NULL)
  {
    m_FiFDialog->Destroy();
    m_FiFDialog = NULL;
  }

  GetFindString();

  std::vector<wxExConfigItem> v;
  v.push_back(
    wxExConfigItem(wxExFindReplaceData::Get()->GetTextFindWhat(),
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  if (id == ID_REPLACE_IN_FILES)
  {
    v.push_back(wxExConfigItem(
      wxExFindReplaceData::Get()->GetTextReplaceWith(),
      CONFIG_COMBOBOX));
  }

  v.push_back(wxExConfigItem(
    m_TextInFiles,
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  v.push_back(wxExConfigItem(
    m_TextInFolder,
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  if (id == ID_REPLACE_IN_FILES)
  {
    // Match whole word does not work with replace.
    std::set<wxString> s;
    s.insert(wxExFindReplaceData::Get()->GetTextMatchCase());
    s.insert(wxExFindReplaceData::Get()->GetTextRegEx());
    v.push_back(wxExConfigItem(s));
  }
  else
  {
    v.push_back(wxExConfigItem(wxExFindReplaceData::Get()->GetInfo()));
  }

  m_FiFDialog = new wxExConfigDialog(this,
    v,
    (id == ID_REPLACE_IN_FILES ? _("Replace In Files"): _("Find In Files")),
    0,
    1,
    wxOK | wxCANCEL,
    id);

  return m_FiFDialog->Show();
}

void wxExFrameWithHistory::OnClose(wxCloseEvent& event)
{
  if (event.CanVeto() && m_Process != NULL)
  {
    if (m_Process->IsRunning())
    {
      wxLogMessage(_("Process is running"));
      event.Veto();
      return;
    }
  }

  wxDELETE(m_Process);

  m_FileHistory.Save(*wxConfigBase::Get());

  for (size_t i = 0; i < m_ProjectHistory.GetCount(); i++)
  {
    wxConfigBase::Get()->Write(
      wxString::Format("RecentProject%d", i),
      m_ProjectHistory.GetHistoryFile(i));
  }

  event.Skip();
}

void wxExFrameWithHistory::OnCommand(wxCommandEvent& event)
{
  if (event.GetId() >= wxID_FILE1 &&
      event.GetId() <= wxID_FILE1 + NUMBER_RECENT_FILES)
  {
    DoRecent(m_FileHistory,
      event.GetId() - wxID_FILE1);
  }
  else if (event.GetId() >= ID_RECENT_PROJECT_LOWEST &&
           event.GetId() <= ID_RECENT_PROJECT_LOWEST + NUMBER_RECENT_PROJECTS)
  {
    DoRecent(m_ProjectHistory,
      event.GetId() - ID_RECENT_PROJECT_LOWEST,
      wxExSTCWithFrame::STC_WIN_IS_PROJECT);
  }
  else
  {
    switch (event.GetId())
    {
    case wxID_OPEN:
      if (!event.GetString().empty())
      {
        wxArrayString files;
        wxStringTokenizer tkz(event.GetString());
        auto* stc = GetSTC();

        while (tkz.HasMoreTokens())
        {
          const wxString token = tkz.GetNextToken();

          wxFileName file(token);

          if (file.IsRelative() && stc != NULL)
          {
            file.MakeAbsolute(stc->GetFileName().GetPath());

            if (!file.FileExists())
            {
              wxLogError(_("Cannot locate file") + ": " + token);
            }
            else
            {
              files.Add(file.GetFullPath());
            }
          }
          else
          {
            files.Add(file.GetFullPath());
          }
        }

        wxExOpenFiles(this, files);
      }
      else
      {
        wxExOpenFilesDialog(this);
      }
      break;

    case ID_PROJECT_SAVE:
      {
        wxExListViewFile* project = GetProject();
        if (project != NULL)
        {
          project->FileSave();
          SetTitle(wxEmptyString, project->GetFileName().GetName());
        }
      }
      break;

    case ID_FIND_IN_FILES:
    case ID_REPLACE_IN_FILES:
      FindInFilesDialog(event.GetId());
      break;

    case ID_TERMINATED_PROCESS:
      wxBell();
      wxDELETE(m_Process);
    break;

    default:
      wxFAIL;
    }
  }
}

void wxExFrameWithHistory::OnCommandConfigDialog(
  wxWindowID dialogid,
  int commandid)
{
  switch (commandid)
  {
    case wxID_CANCEL:
      if (wxExDir::GetIsBusy())
      {
        wxExDir::Cancel();
#if wxUSE_STATUSBAR
        wxExFrame::StatusText(_("Cancelled"));
#endif
      }
      break;

    case wxID_OK:
      switch (dialogid)
      {
        case wxID_ADD:
          GetProject()->AddItems();
          break;

        case ID_FIND_IN_FILES:
        case ID_REPLACE_IN_FILES:
          FindInFiles(dialogid);
          break;

        default: wxFAIL;
      }
      break;

    default: wxFAIL;
  }
}

void wxExFrameWithHistory::OnIdle(wxIdleEvent& event)
{
  event.Skip();

  auto* stc = GetFocusedSTC();
  auto* project = GetProject();

  const wxString title(GetTitle());
  const wxUniChar indicator('*');

  if ((project != NULL && project->GetContentsChanged()) ||
       // using GetContentsChanged gives assert in vcs dialog
      (stc != NULL && stc->GetModify()))
  {
    // Project or editor changed, add indicator if not yet done.
    if (title.Last() != indicator)
    {
      wxFrame::SetTitle(title + " " + indicator);
    }
  }
  else
  {
    // Project or editor not changed, remove indicator if not yet done.
    if (title.Last() == indicator)
    {
      wxFrame::SetTitle(title.substr(0, title.length() - 2));
    }
  }
}

bool wxExFrameWithHistory::OpenFile(
  const wxExFileName& filename,
  int line_number,
  const wxString& match,
  long flags)
{
  if (wxExManagedFrame::OpenFile(filename, line_number, match, flags))
  {
    SetRecentFile(filename.GetFullPath());
    return true;
  }

  return false;
}

int wxExFrameWithHistory::ProcessConfigDialog(
  wxWindow* parent,
  const wxString& title) const
{
  return wxExProcess::ConfigDialog(parent, title);
}

bool wxExFrameWithHistory::ProcessIsRunning() const
{
  return (m_Process != NULL && m_Process->IsRunning());
}

bool wxExFrameWithHistory::ProcessIsSelected() const
{
  return wxExProcess::IsSelected();
}

bool wxExFrameWithHistory::ProcessRun(const wxString& command)
{
  wxASSERT(m_Process == NULL);

  if ((m_Process = new wxExProcess(this, command)) != NULL)
  {
    if (m_Process->Execute() > 0)
    {
      return true;
    }

    wxDELETE(m_Process);
  }

  return false;
}

bool wxExFrameWithHistory::ProcessStop()
{
  if (m_Process->IsRunning())
  {
    if (m_Process->Kill() == wxKILL_ERROR)
    {
      // Even if the process could not be killed, set it to NULL, as it is deleted.
      wxFAIL;
      m_Process = NULL;
      return false;
    }
    else
    {
      m_Process = NULL;
      return true;
    }
  }

  return true;
}

void wxExFrameWithHistory::SetRecentFile(const wxString& file)
{
  if (!file.empty())
  {
    m_FileHistory.AddFileToHistory(file);

    if (m_FileHistoryList != NULL)
    {
      wxExListItem item(m_FileHistoryList, file);
      item.Insert((long)0);

      if (m_FileHistoryList->GetItemCount() > 1)
      {
        for (auto i = m_FileHistoryList->GetItemCount() - 1; i >= 1 ; i--)
        {
          wxExListItem item(m_FileHistoryList, i);

          if (item.GetFileName().GetFullPath() == file)
          {
            m_FileHistoryList->DeleteItem(i);
          }
        }
      }
    }
  }
}

void wxExFrameWithHistory::SetTitle(
  const wxString& file,
  const wxString& project)
{
  // If one of the strings is empty, try to get a better string.
  wxString better_file(file);
  wxString better_project(project);

  if (better_file.empty())
  {
    auto* stc = GetSTC();

    if (stc != NULL)
    {
      better_file = stc->GetFileName().GetFullPath();
    }
  }

  if (better_project.empty())
  {
    wxExListViewFile* lv = (wxExListViewFile*)GetListView();

    if (lv != NULL && lv->GetType() == wxExListViewStandard::LIST_FILE)
    {
      better_project = lv->GetFileName().GetName();
    }
  }

  // And now update the title.
  if (better_file.empty() && better_project.empty())
  {
    wxExFrame::SetTitle(wxTheApp->GetAppName());
  }
  else
  {
    const wxString sep =
      (!better_file.empty() && !better_project.empty() ?
          wxString(" - "):
          wxString(wxEmptyString));

    wxExFrame::SetTitle(better_file + sep + better_project);
  }
}

void wxExFrameWithHistory::UseFileHistory(wxWindowID id, wxMenu* menu)
{
  UseHistory(id, menu, m_FileHistory);

  // We can load file history now.
  m_FileHistory.Load(*wxConfigBase::Get());
}

void wxExFrameWithHistory::UseFileHistoryList(wxExListView* list)
{
  m_FileHistoryList = list;
  m_FileHistoryList->Hide();

  // Add all (existing) items from FileHistory.
  for (size_t i = 0; i < m_FileHistory.GetCount(); i++)
  {
    wxExListItem item(
      m_FileHistoryList,
      m_FileHistory.GetHistoryFile(i));

    if (item.GetFileName().GetStat().IsOk())
    {
      item.Insert();
    }
  }
}

void wxExFrameWithHistory::UseHistory(
  wxWindowID id,
  wxMenu* menu,
  wxFileHistory& history)
{
  wxMenu* submenu = new wxMenu;
  menu->Append(id, _("Open &Recent"), submenu);
  history.UseMenu(submenu);
}

void wxExFrameWithHistory::UseProjectHistory(wxWindowID id, wxMenu* menu)
{
  UseHistory(id, menu, m_ProjectHistory);

  // And add the files to the menu.
  m_ProjectHistory.AddFilesToMenu();
}
<commit_msg>fixed crash when stopping not running process<commit_after>/******************************************************************************\
* File:          frame.cpp
* Purpose:       Implementation of wxExFrameWithHistory class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/config.h>
#include <wx/tokenzr.h>
#include <wx/extension/configdlg.h>
#include <wx/extension/frd.h>
#include <wx/extension/log.h>
#include <wx/extension/util.h>
#include <wx/extension/report/frame.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/dir.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listviewfile.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/stc.h>
#include <wx/extension/report/util.h>

// The maximal number of files and projects to be supported.
const int NUMBER_RECENT_FILES = 25;
const int NUMBER_RECENT_PROJECTS = 25;
const int ID_RECENT_PROJECT_LOWEST =  wxID_FILE1 + NUMBER_RECENT_FILES + 1;

BEGIN_EVENT_TABLE(wxExFrameWithHistory, wxExManagedFrame)
  EVT_CLOSE(wxExFrameWithHistory::OnClose)
  EVT_IDLE(wxExFrameWithHistory::OnIdle)
  EVT_MENU(wxID_OPEN, wxExFrameWithHistory::OnCommand)
  EVT_MENU(ID_TERMINATED_PROCESS, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    wxID_FILE1,
    wxID_FILE1 + NUMBER_RECENT_FILES, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    ID_RECENT_PROJECT_LOWEST,
    ID_RECENT_PROJECT_LOWEST + NUMBER_RECENT_PROJECTS, wxExFrameWithHistory::OnCommand)
  EVT_MENU_RANGE(
    ID_EXTENSION_REPORT_LOWEST,
    ID_EXTENSION_REPORT_HIGHEST,
    wxExFrameWithHistory::OnCommand)
END_EVENT_TABLE()

wxExFrameWithHistory::wxExFrameWithHistory(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  size_t maxFiles,
  size_t maxProjects,
  int style)
  : wxExManagedFrame(parent, id, title, style)
  , m_FiFDialog(NULL)
  , m_TextInFiles(_("In files"))
  , m_TextInFolder(_("In folder"))
  , m_FileHistory(maxFiles, wxID_FILE1)
  , m_FileHistoryList(NULL)
  , m_ProjectHistory(maxProjects, ID_RECENT_PROJECT_LOWEST)
  , m_Process(NULL)
{
  // There is only support for one history in the config.
  // We use file history for this, so update project history ourselves.
  // The order should be inverted, as the last one added is the most recent used.
  for (int i = m_ProjectHistory.GetMaxFiles() - 1 ; i >=0 ; i--)
  {
    SetRecentProject(
      wxConfigBase::Get()->Read(wxString::Format("RecentProject%d", i)));
  }

#ifdef wxExUSE_EMBEDDED_SQL
  wxExTool::Get()->AddInfo(
    ID_TOOL_SQL,
    _("Executed %ld SQL queries in"),
    wxExEllipsed(_("&SQL Query Run")));

  wxExTool::Get()->AddInfo(
    ID_TOOL_REPORT_SQL,
    _("Reported %ld SQL queries in"),
    _("Report SQL &Query"));
#endif
}

wxExFrameWithHistory::~wxExFrameWithHistory()
{
  if (m_FiFDialog != NULL)
  {
    m_FiFDialog->Destroy();
  }
}

void wxExFrameWithHistory::DoRecent(
  wxFileHistory& history,
  int index,
  long flags)
{
  if (history.GetCount() > 0)
  {
    const wxString file(history.GetHistoryFile(index));

    if (!wxFileExists(file))
    {
      history.RemoveFileFromHistory(index);
      wxLogMessage(_("Removed not existing file: %s from history"),
        file.c_str());
    }
    else
    {
      OpenFile(file, 0, wxEmptyString, flags);
    }
  }
}

void wxExFrameWithHistory::FindInFiles(wxWindowID dialogid)
{
  const bool replace = (dialogid == ID_REPLACE_IN_FILES);
  const wxExTool tool =
    (replace ?
       ID_TOOL_REPORT_REPLACE:
       ID_TOOL_REPORT_FIND);

  if (!wxExTextFileWithListView::SetupTool(tool, this))
  {
    return;
  }

  wxExLog::Get()->Log(
    wxExFindReplaceData::Get()->GetFindReplaceInfoText(replace));

  wxExDirTool dir(
    tool,
    wxExConfigFirstOf(m_TextInFolder),
    wxExConfigFirstOf(m_TextInFiles));

  dir.FindFiles();

  tool.Log(
    &dir.GetStatistics().GetElements(),
    wxExConfigFirstOf(m_TextInFolder));
}

int wxExFrameWithHistory::FindInFilesDialog(int id)
{
  if (m_FiFDialog != NULL)
  {
    m_FiFDialog->Destroy();
    m_FiFDialog = NULL;
  }

  GetFindString();

  std::vector<wxExConfigItem> v;
  v.push_back(
    wxExConfigItem(wxExFindReplaceData::Get()->GetTextFindWhat(),
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  if (id == ID_REPLACE_IN_FILES)
  {
    v.push_back(wxExConfigItem(
      wxExFindReplaceData::Get()->GetTextReplaceWith(),
      CONFIG_COMBOBOX));
  }

  v.push_back(wxExConfigItem(
    m_TextInFiles,
    CONFIG_COMBOBOX,
    wxEmptyString,
    true));

  v.push_back(wxExConfigItem(
    m_TextInFolder,
    CONFIG_COMBOBOXDIR,
    wxEmptyString,
    true,
    1000));

  if (id == ID_REPLACE_IN_FILES)
  {
    // Match whole word does not work with replace.
    std::set<wxString> s;
    s.insert(wxExFindReplaceData::Get()->GetTextMatchCase());
    s.insert(wxExFindReplaceData::Get()->GetTextRegEx());
    v.push_back(wxExConfigItem(s));
  }
  else
  {
    v.push_back(wxExConfigItem(wxExFindReplaceData::Get()->GetInfo()));
  }

  m_FiFDialog = new wxExConfigDialog(this,
    v,
    (id == ID_REPLACE_IN_FILES ? _("Replace In Files"): _("Find In Files")),
    0,
    1,
    wxOK | wxCANCEL,
    id);

  return m_FiFDialog->Show();
}

void wxExFrameWithHistory::OnClose(wxCloseEvent& event)
{
  if (event.CanVeto() && m_Process != NULL)
  {
    if (m_Process->IsRunning())
    {
      wxLogMessage(_("Process is running"));
      event.Veto();
      return;
    }
  }

  wxDELETE(m_Process);

  m_FileHistory.Save(*wxConfigBase::Get());

  for (size_t i = 0; i < m_ProjectHistory.GetCount(); i++)
  {
    wxConfigBase::Get()->Write(
      wxString::Format("RecentProject%d", i),
      m_ProjectHistory.GetHistoryFile(i));
  }

  event.Skip();
}

void wxExFrameWithHistory::OnCommand(wxCommandEvent& event)
{
  if (event.GetId() >= wxID_FILE1 &&
      event.GetId() <= wxID_FILE1 + NUMBER_RECENT_FILES)
  {
    DoRecent(m_FileHistory,
      event.GetId() - wxID_FILE1);
  }
  else if (event.GetId() >= ID_RECENT_PROJECT_LOWEST &&
           event.GetId() <= ID_RECENT_PROJECT_LOWEST + NUMBER_RECENT_PROJECTS)
  {
    DoRecent(m_ProjectHistory,
      event.GetId() - ID_RECENT_PROJECT_LOWEST,
      wxExSTCWithFrame::STC_WIN_IS_PROJECT);
  }
  else
  {
    switch (event.GetId())
    {
    case wxID_OPEN:
      if (!event.GetString().empty())
      {
        wxArrayString files;
        wxStringTokenizer tkz(event.GetString());
        auto* stc = GetSTC();

        while (tkz.HasMoreTokens())
        {
          const wxString token = tkz.GetNextToken();

          wxFileName file(token);

          if (file.IsRelative() && stc != NULL)
          {
            file.MakeAbsolute(stc->GetFileName().GetPath());

            if (!file.FileExists())
            {
              wxLogError(_("Cannot locate file") + ": " + token);
            }
            else
            {
              files.Add(file.GetFullPath());
            }
          }
          else
          {
            files.Add(file.GetFullPath());
          }
        }

        wxExOpenFiles(this, files);
      }
      else
      {
        wxExOpenFilesDialog(this);
      }
      break;

    case ID_PROJECT_SAVE:
      {
        wxExListViewFile* project = GetProject();
        if (project != NULL)
        {
          project->FileSave();
          SetTitle(wxEmptyString, project->GetFileName().GetName());
        }
      }
      break;

    case ID_FIND_IN_FILES:
    case ID_REPLACE_IN_FILES:
      FindInFilesDialog(event.GetId());
      break;

    case ID_TERMINATED_PROCESS:
      wxBell();
      wxDELETE(m_Process);
    break;

    default:
      wxFAIL;
    }
  }
}

void wxExFrameWithHistory::OnCommandConfigDialog(
  wxWindowID dialogid,
  int commandid)
{
  switch (commandid)
  {
    case wxID_CANCEL:
      if (wxExDir::GetIsBusy())
      {
        wxExDir::Cancel();
#if wxUSE_STATUSBAR
        wxExFrame::StatusText(_("Cancelled"));
#endif
      }
      break;

    case wxID_OK:
      switch (dialogid)
      {
        case wxID_ADD:
          GetProject()->AddItems();
          break;

        case ID_FIND_IN_FILES:
        case ID_REPLACE_IN_FILES:
          FindInFiles(dialogid);
          break;

        default: wxFAIL;
      }
      break;

    default: wxFAIL;
  }
}

void wxExFrameWithHistory::OnIdle(wxIdleEvent& event)
{
  event.Skip();

  auto* stc = GetFocusedSTC();
  auto* project = GetProject();

  const wxString title(GetTitle());
  const wxUniChar indicator('*');

  if ((project != NULL && project->GetContentsChanged()) ||
       // using GetContentsChanged gives assert in vcs dialog
      (stc != NULL && stc->GetModify()))
  {
    // Project or editor changed, add indicator if not yet done.
    if (title.Last() != indicator)
    {
      wxFrame::SetTitle(title + " " + indicator);
    }
  }
  else
  {
    // Project or editor not changed, remove indicator if not yet done.
    if (title.Last() == indicator)
    {
      wxFrame::SetTitle(title.substr(0, title.length() - 2));
    }
  }
}

bool wxExFrameWithHistory::OpenFile(
  const wxExFileName& filename,
  int line_number,
  const wxString& match,
  long flags)
{
  if (wxExManagedFrame::OpenFile(filename, line_number, match, flags))
  {
    SetRecentFile(filename.GetFullPath());
    return true;
  }

  return false;
}

int wxExFrameWithHistory::ProcessConfigDialog(
  wxWindow* parent,
  const wxString& title) const
{
  return wxExProcess::ConfigDialog(parent, title);
}

bool wxExFrameWithHistory::ProcessIsRunning() const
{
  return (m_Process != NULL && m_Process->IsRunning());
}

bool wxExFrameWithHistory::ProcessIsSelected() const
{
  return wxExProcess::IsSelected();
}

bool wxExFrameWithHistory::ProcessRun(const wxString& command)
{
  wxASSERT(m_Process == NULL);

  if ((m_Process = new wxExProcess(this, command)) != NULL)
  {
    if (m_Process->Execute() > 0)
    {
      return true;
    }

    wxDELETE(m_Process);
  }

  return false;
}

bool wxExFrameWithHistory::ProcessStop()
{
  if (m_Process == NULL)
  {
    return true;
  }
  else if (m_Process->IsRunning())
  {
    if (m_Process->Kill() == wxKILL_ERROR)
    {
      // Even if the process could not be killed, set it to NULL, as it is deleted.
      wxFAIL;
      m_Process = NULL;
      return false;
    }
    else
    {
      m_Process = NULL;
      return true;
    }

    return true;
  }
}

void wxExFrameWithHistory::SetRecentFile(const wxString& file)
{
  if (!file.empty())
  {
    m_FileHistory.AddFileToHistory(file);

    if (m_FileHistoryList != NULL)
    {
      wxExListItem item(m_FileHistoryList, file);
      item.Insert((long)0);

      if (m_FileHistoryList->GetItemCount() > 1)
      {
        for (auto i = m_FileHistoryList->GetItemCount() - 1; i >= 1 ; i--)
        {
          wxExListItem item(m_FileHistoryList, i);

          if (item.GetFileName().GetFullPath() == file)
          {
            m_FileHistoryList->DeleteItem(i);
          }
        }
      }
    }
  }
}

void wxExFrameWithHistory::SetTitle(
  const wxString& file,
  const wxString& project)
{
  // If one of the strings is empty, try to get a better string.
  wxString better_file(file);
  wxString better_project(project);

  if (better_file.empty())
  {
    auto* stc = GetSTC();

    if (stc != NULL)
    {
      better_file = stc->GetFileName().GetFullPath();
    }
  }

  if (better_project.empty())
  {
    wxExListViewFile* lv = (wxExListViewFile*)GetListView();

    if (lv != NULL && lv->GetType() == wxExListViewStandard::LIST_FILE)
    {
      better_project = lv->GetFileName().GetName();
    }
  }

  // And now update the title.
  if (better_file.empty() && better_project.empty())
  {
    wxExFrame::SetTitle(wxTheApp->GetAppName());
  }
  else
  {
    const wxString sep =
      (!better_file.empty() && !better_project.empty() ?
          wxString(" - "):
          wxString(wxEmptyString));

    wxExFrame::SetTitle(better_file + sep + better_project);
  }
}

void wxExFrameWithHistory::UseFileHistory(wxWindowID id, wxMenu* menu)
{
  UseHistory(id, menu, m_FileHistory);

  // We can load file history now.
  m_FileHistory.Load(*wxConfigBase::Get());
}

void wxExFrameWithHistory::UseFileHistoryList(wxExListView* list)
{
  m_FileHistoryList = list;
  m_FileHistoryList->Hide();

  // Add all (existing) items from FileHistory.
  for (size_t i = 0; i < m_FileHistory.GetCount(); i++)
  {
    wxExListItem item(
      m_FileHistoryList,
      m_FileHistory.GetHistoryFile(i));

    if (item.GetFileName().GetStat().IsOk())
    {
      item.Insert();
    }
  }
}

void wxExFrameWithHistory::UseHistory(
  wxWindowID id,
  wxMenu* menu,
  wxFileHistory& history)
{
  wxMenu* submenu = new wxMenu;
  menu->Append(id, _("Open &Recent"), submenu);
  history.UseMenu(submenu);
}

void wxExFrameWithHistory::UseProjectHistory(wxWindowID id, wxMenu* menu)
{
  UseHistory(id, menu, m_ProjectHistory);

  // And add the files to the menu.
  m_ProjectHistory.AddFilesToMenu();
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2018-2019 Intel Corporation                                    //
//                                                                          //
// 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 <iterator>
#include <memory>
#include <random>
#include "GLFWOSPRayWindow.h"

#include "ospray_testing.h"

#include <imgui.h>

using namespace ospcommon;

OSPGeometry createGroundPlaneGeometry()
{
  OSPGeometry planeGeometry = ospNewGeometry("quads");

  struct Vertex
  {
    vec3f position;
    vec3f normal;
    vec4f color;
  };

  struct QuadIndex
  {
    int x;
    int y;
    int z;
    int w;
  };

  std::vector<Vertex> vertices;
  std::vector<QuadIndex> quadIndices;

  // ground plane
  int startingIndex = vertices.size();

  // extent of plane in the (x, z) directions
  const float planeExtent = 1.5f;

  const vec3f up   = vec3f{0.f, 1.f, 0.f};
  const vec4f gray = vec4f{0.9f, 0.9f, 0.9f, 0.75f};

  vertices.push_back(Vertex{vec3f{-planeExtent, -1.f, -planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{planeExtent, -1.f, -planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{planeExtent, -1.f, planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{-planeExtent, -1.f, planeExtent}, up, gray});

  quadIndices.push_back(QuadIndex{
      startingIndex, startingIndex + 1, startingIndex + 2, startingIndex + 3});

  // stripes on ground plane
  const float stripeWidth  = 0.025f;
  const float paddedExtent = planeExtent + stripeWidth;
  const size_t numStripes  = 10;

  const vec4f stripeColor = vec4f{1.0f, 0.1f, 0.1f, 1.f};

  for (size_t i = 0; i < numStripes; i++) {
    // the center coordinate of the stripe, either in the x or z direction
    const float coord =
        -planeExtent + float(i) / float(numStripes - 1) * 2.f * planeExtent;

    // offset the stripes by an epsilon above the ground plane
    const float yLevel = -1.f + 1e-3f;

    // x-direction stripes
    startingIndex = vertices.size();

    vertices.push_back(Vertex{
        vec3f{-paddedExtent, yLevel, coord - stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{paddedExtent, yLevel, coord - stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{paddedExtent, yLevel, coord + stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{-paddedExtent, yLevel, coord + stripeWidth}, up, stripeColor});

    quadIndices.push_back(QuadIndex{startingIndex,
                                    startingIndex + 1,
                                    startingIndex + 2,
                                    startingIndex + 3});

    // z-direction stripes
    startingIndex = vertices.size();

    vertices.push_back(Vertex{
        vec3f{coord - stripeWidth, yLevel, -paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord + stripeWidth, yLevel, -paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord + stripeWidth, yLevel, paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord - stripeWidth, yLevel, paddedExtent}, up, stripeColor});

    quadIndices.push_back(QuadIndex{startingIndex,
                                    startingIndex + 1,
                                    startingIndex + 2,
                                    startingIndex + 3});
  }

  // create OSPRay data objects
  std::vector<vec3f> positionVector;
  std::vector<vec3f> normalVector;
  std::vector<vec4f> colorVector;

  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(positionVector),
                 [](Vertex const &v) { return v.position; });
  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(normalVector),
                 [](Vertex const &v) { return v.normal; });
  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(colorVector),
                 [](Vertex const &v) { return v.color; });

  OSPData positionData =
      ospNewData(vertices.size(), OSP_FLOAT3, positionVector.data());
  OSPData normalData =
      ospNewData(vertices.size(), OSP_FLOAT3, normalVector.data());
  OSPData colorData =
      ospNewData(vertices.size(), OSP_FLOAT4, colorVector.data());
  OSPData indexData =
      ospNewData(quadIndices.size(), OSP_INT4, quadIndices.data());

  // set vertex / index data on the geometry
  ospSetData(planeGeometry, "vertex", positionData);
  ospSetData(planeGeometry, "vertex.normal", normalData);
  ospSetData(planeGeometry, "vertex.color", colorData);
  ospSetData(planeGeometry, "index", indexData);

  // create and assign a material to the geometry
  OSPMaterial material = ospNewMaterial2("scivis", "OBJMaterial");
  ospCommit(material);

  ospSetMaterial(planeGeometry, material);

  // finally, commit the geometry
  ospCommit(planeGeometry);

  // release handles we no longer need
  ospRelease(positionData);
  ospRelease(normalData);
  ospRelease(colorData);
  ospRelease(indexData);
  ospRelease(material);

  return planeGeometry;
}

int main(int argc, const char **argv)
{
  // initialize OSPRay; OSPRay parses (and removes) its commandline parameters,
  // e.g. "--osp:debug"
  OSPError initError = ospInit(&argc, argv);

  if (initError != OSP_NO_ERROR)
    return initError;

  // set an error callback to catch any OSPRay errors and exit the application
  ospDeviceSetErrorFunc(
      ospGetCurrentDevice(), [](OSPError error, const char *errorDetails) {
        std::cerr << "OSPRay error: " << errorDetails << std::endl;
        exit(error);
      });

  // create the "world" model which will contain all of our geometries
  OSPModel world = ospNewModel();

  // add in subdivision geometry
  OSPTestingGeometry subdivisionGeometry =
      ospTestingNewGeometry("subdivision_cube", "scivis");
  ospAddGeometry(world, subdivisionGeometry.geometry);
  ospRelease(subdivisionGeometry.geometry);

  // add in a ground plane geometry
  ospAddGeometry(world, createGroundPlaneGeometry());

  // commit the world model
  ospCommit(world);

  // create OSPRay renderer
  OSPRenderer renderer = ospNewRenderer("scivis");

  OSPData lightsData = ospTestingNewLights("ambient_and_directional");
  ospSetData(renderer, "lights", lightsData);
  ospRelease(lightsData);

  ospCommit(renderer);

  // create a GLFW OSPRay window: this object will create and manage the OSPRay
  // frame buffer and camera directly
  auto glfwOSPRayWindow =
      std::unique_ptr<GLFWOSPRayWindow>(new GLFWOSPRayWindow(
          vec2i{1024, 768}, box3f(vec3f(-1.f), vec3f(1.f)), world, renderer));

  glfwOSPRayWindow->registerImGuiCallback([=]() {
    static int spp = 1;
    if (ImGui::SliderInt("spp", &spp, 1, 64)) {
      ospSet1i(renderer, "spp", spp);
      ospCommit(renderer);
    }

    static float subdivisionLevel = 1.f;
    if (ImGui::SliderFloat("subdivision level", &subdivisionLevel, 1.f, 25.f)) {
      ospSet1f(subdivisionGeometry.geometry, "level", subdivisionLevel);
      ospCommit(subdivisionGeometry.geometry);
      ospCommit(world);

      GLFWOSPRayWindow::getActiveWindow()->clearFrameBuffer();
    }
  });

  // start the GLFW main loop, which will continuously render
  glfwOSPRayWindow->mainLoop();

  // cleanup remaining objects
  ospRelease(world);
  ospRelease(renderer);

  // cleanly shut OSPRay down
  ospShutdown();

  return 0;
}
<commit_msg>using ints for subdivision level slider.<commit_after>// ======================================================================== //
// Copyright 2018-2019 Intel Corporation                                    //
//                                                                          //
// 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 <iterator>
#include <memory>
#include <random>
#include "GLFWOSPRayWindow.h"

#include "ospray_testing.h"

#include <imgui.h>

using namespace ospcommon;

OSPGeometry createGroundPlaneGeometry()
{
  OSPGeometry planeGeometry = ospNewGeometry("quads");

  struct Vertex
  {
    vec3f position;
    vec3f normal;
    vec4f color;
  };

  struct QuadIndex
  {
    int x;
    int y;
    int z;
    int w;
  };

  std::vector<Vertex> vertices;
  std::vector<QuadIndex> quadIndices;

  // ground plane
  int startingIndex = vertices.size();

  // extent of plane in the (x, z) directions
  const float planeExtent = 1.5f;

  const vec3f up   = vec3f{0.f, 1.f, 0.f};
  const vec4f gray = vec4f{0.9f, 0.9f, 0.9f, 0.75f};

  vertices.push_back(Vertex{vec3f{-planeExtent, -1.f, -planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{planeExtent, -1.f, -planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{planeExtent, -1.f, planeExtent}, up, gray});
  vertices.push_back(Vertex{vec3f{-planeExtent, -1.f, planeExtent}, up, gray});

  quadIndices.push_back(QuadIndex{
      startingIndex, startingIndex + 1, startingIndex + 2, startingIndex + 3});

  // stripes on ground plane
  const float stripeWidth  = 0.025f;
  const float paddedExtent = planeExtent + stripeWidth;
  const size_t numStripes  = 10;

  const vec4f stripeColor = vec4f{1.0f, 0.1f, 0.1f, 1.f};

  for (size_t i = 0; i < numStripes; i++) {
    // the center coordinate of the stripe, either in the x or z direction
    const float coord =
        -planeExtent + float(i) / float(numStripes - 1) * 2.f * planeExtent;

    // offset the stripes by an epsilon above the ground plane
    const float yLevel = -1.f + 1e-3f;

    // x-direction stripes
    startingIndex = vertices.size();

    vertices.push_back(Vertex{
        vec3f{-paddedExtent, yLevel, coord - stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{paddedExtent, yLevel, coord - stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{paddedExtent, yLevel, coord + stripeWidth}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{-paddedExtent, yLevel, coord + stripeWidth}, up, stripeColor});

    quadIndices.push_back(QuadIndex{startingIndex,
                                    startingIndex + 1,
                                    startingIndex + 2,
                                    startingIndex + 3});

    // z-direction stripes
    startingIndex = vertices.size();

    vertices.push_back(Vertex{
        vec3f{coord - stripeWidth, yLevel, -paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord + stripeWidth, yLevel, -paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord + stripeWidth, yLevel, paddedExtent}, up, stripeColor});
    vertices.push_back(Vertex{
        vec3f{coord - stripeWidth, yLevel, paddedExtent}, up, stripeColor});

    quadIndices.push_back(QuadIndex{startingIndex,
                                    startingIndex + 1,
                                    startingIndex + 2,
                                    startingIndex + 3});
  }

  // create OSPRay data objects
  std::vector<vec3f> positionVector;
  std::vector<vec3f> normalVector;
  std::vector<vec4f> colorVector;

  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(positionVector),
                 [](Vertex const &v) { return v.position; });
  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(normalVector),
                 [](Vertex const &v) { return v.normal; });
  std::transform(vertices.begin(),
                 vertices.end(),
                 std::back_inserter(colorVector),
                 [](Vertex const &v) { return v.color; });

  OSPData positionData =
      ospNewData(vertices.size(), OSP_FLOAT3, positionVector.data());
  OSPData normalData =
      ospNewData(vertices.size(), OSP_FLOAT3, normalVector.data());
  OSPData colorData =
      ospNewData(vertices.size(), OSP_FLOAT4, colorVector.data());
  OSPData indexData =
      ospNewData(quadIndices.size(), OSP_INT4, quadIndices.data());

  // set vertex / index data on the geometry
  ospSetData(planeGeometry, "vertex", positionData);
  ospSetData(planeGeometry, "vertex.normal", normalData);
  ospSetData(planeGeometry, "vertex.color", colorData);
  ospSetData(planeGeometry, "index", indexData);

  // create and assign a material to the geometry
  OSPMaterial material = ospNewMaterial2("scivis", "OBJMaterial");
  ospCommit(material);

  ospSetMaterial(planeGeometry, material);

  // finally, commit the geometry
  ospCommit(planeGeometry);

  // release handles we no longer need
  ospRelease(positionData);
  ospRelease(normalData);
  ospRelease(colorData);
  ospRelease(indexData);
  ospRelease(material);

  return planeGeometry;
}

int main(int argc, const char **argv)
{
  // initialize OSPRay; OSPRay parses (and removes) its commandline parameters,
  // e.g. "--osp:debug"
  OSPError initError = ospInit(&argc, argv);

  if (initError != OSP_NO_ERROR)
    return initError;

  // set an error callback to catch any OSPRay errors and exit the application
  ospDeviceSetErrorFunc(
      ospGetCurrentDevice(), [](OSPError error, const char *errorDetails) {
        std::cerr << "OSPRay error: " << errorDetails << std::endl;
        exit(error);
      });

  // create the "world" model which will contain all of our geometries
  OSPModel world = ospNewModel();

  // add in subdivision geometry
  OSPTestingGeometry subdivisionGeometry =
      ospTestingNewGeometry("subdivision_cube", "scivis");
  ospAddGeometry(world, subdivisionGeometry.geometry);
  ospRelease(subdivisionGeometry.geometry);

  // add in a ground plane geometry
  ospAddGeometry(world, createGroundPlaneGeometry());

  // commit the world model
  ospCommit(world);

  // create OSPRay renderer
  OSPRenderer renderer = ospNewRenderer("scivis");

  OSPData lightsData = ospTestingNewLights("ambient_and_directional");
  ospSetData(renderer, "lights", lightsData);
  ospRelease(lightsData);

  ospCommit(renderer);

  // create a GLFW OSPRay window: this object will create and manage the OSPRay
  // frame buffer and camera directly
  auto glfwOSPRayWindow =
      std::unique_ptr<GLFWOSPRayWindow>(new GLFWOSPRayWindow(
          vec2i{1024, 768}, box3f(vec3f(-1.f), vec3f(1.f)), world, renderer));

  glfwOSPRayWindow->registerImGuiCallback([=]() {
    static int spp = 1;
    if (ImGui::SliderInt("spp", &spp, 1, 64)) {
      ospSet1i(renderer, "spp", spp);
      ospCommit(renderer);
    }

    static int subdivisionLevel = 5;
    if (ImGui::SliderInt("subdivision level", &subdivisionLevel, 1, 10)) {
      ospSet1f(subdivisionGeometry.geometry, "level", subdivisionLevel);
      ospCommit(subdivisionGeometry.geometry);
      ospCommit(world);

      GLFWOSPRayWindow::getActiveWindow()->clearFrameBuffer();
    }
  });

  // start the GLFW main loop, which will continuously render
  glfwOSPRayWindow->mainLoop();

  // cleanup remaining objects
  ospRelease(world);
  ospRelease(renderer);

  // cleanly shut OSPRay down
  ospShutdown();

  return 0;
}
<|endoftext|>