<commit_before>#include "tiny_ui.h"
#include <stdio.h>

class MyWindow: public Window, public ClickInterface, public IoWatchInterface,
                public TimerInterface, public ListBoxInterface
{
public:
    MyWindow() :
        Window("Hello world"),
        m_mainbox(VERTICAL),
        m_quitbutton("Quit"),
        m_watch(0),
        m_timer(1000)
    {
        for (int i = 0; i < 5; ++i) {
            m_items[i].set_text("item " + format_number(i));
            m_listbox.add_item(&m_items[i]);

            m_buttons[i].set_label("label " + format_number(i));
            m_buttons[i].set_handler(this);
            m_mainbox.add_widget(&m_buttons[i]);
        }
        m_listbox.set_handler(this);
        m_quitbutton.set_handler(this);
        m_watch.set_handler(this);
        m_timer.set_handler(this);
        m_mainbox.add_widget(&m_listbox);
        m_mainbox.add_widget(&m_quitbutton);
        set_widget(&m_mainbox);
    }

private:
    BoxLayout m_mainbox;
    ListBox m_listbox;
    ListBoxItem m_items[5];
    Button m_buttons[5];
    Button m_quitbutton;
    IoWatch m_watch;
    Timer m_timer;

    void clicked(Button *button)
    {
        if (button == &m_quitbutton)
            Application::instance()->quit();
    }
    void ready(IoWatch *watch)
    {
        UNUSED(watch);
        char buf[256];
        ssize_t len = read(0, buf, sizeof(buf) - 1);
        if (len == 0)
            Application::instance()->quit();
        while (len > 0 && buf[len - 1] == '\n')
            len--;
        buf[len] = 0;
        printf("<%s>\n", buf);
    }
    void timeout(Timer *timer)
    {
        UNUSED(timer);
        printf("tick!\n");
    }
    void clicked(ListBox *listbox, ListBoxItem *item)
    {
        UNUSED(listbox);
        for (int i = 0; i < 5; ++i) {
            if (&m_items[i] == item)
                printf("%d clicked\n", i);
        }
    }
};

int main(int argc, char **argv)
{
    Application app(&argc, &argv);
    SigIntHandler sighandler;
    sighandler.set_handler(&app);
    MyWindow mw;
    mw.show();
    return app.run();
}
<commit_msg>test: Make event interfaces private [CLEANUP]<commit_after>#include "tiny_ui.h"
#include <stdio.h>

class MyWindow: public Window, private ClickInterface, private IoWatchInterface,
                private TimerInterface, private ListBoxInterface
{
public:
    MyWindow() :
        Window("Hello world"),
        m_mainbox(VERTICAL),
        m_quitbutton("Quit"),
        m_watch(0),
        m_timer(1000)
    {
        for (int i = 0; i < 5; ++i) {
            m_items[i].set_text("item " + format_number(i));
            m_listbox.add_item(&m_items[i]);

            m_buttons[i].set_label("label " + format_number(i));
            m_buttons[i].set_handler(this);
            m_mainbox.add_widget(&m_buttons[i]);
        }
        m_listbox.set_handler(this);
        m_quitbutton.set_handler(this);
        m_watch.set_handler(this);
        m_timer.set_handler(this);
        m_mainbox.add_widget(&m_listbox);
        m_mainbox.add_widget(&m_quitbutton);
        set_widget(&m_mainbox);
    }

private:
    BoxLayout m_mainbox;
    ListBox m_listbox;
    ListBoxItem m_items[5];
    Button m_buttons[5];
    Button m_quitbutton;
    IoWatch m_watch;
    Timer m_timer;

    void clicked(Button *button)
    {
        if (button == &m_quitbutton)
            Application::instance()->quit();
    }
    void ready(IoWatch *watch)
    {
        UNUSED(watch);
        char buf[256];
        ssize_t len = read(0, buf, sizeof(buf) - 1);
        if (len == 0)
            Application::instance()->quit();
        while (len > 0 && buf[len - 1] == '\n')
            len--;
        buf[len] = 0;
        printf("<%s>\n", buf);
    }
    void timeout(Timer *timer)
    {
        UNUSED(timer);
        printf("tick!\n");
    }
    void clicked(ListBox *listbox, ListBoxItem *item)
    {
        UNUSED(listbox);
        for (int i = 0; i < 5; ++i) {
            if (&m_items[i] == item)
                printf("%d clicked\n", i);
        }
    }
};

int main(int argc, char **argv)
{
    Application app(&argc, &argv);
    SigIntHandler sighandler;
    sighandler.set_handler(&app);
    MyWindow mw;
    mw.show();
    return app.run();
}
<|endoftext|>


<commit_before>#include <fstream>
#include <string>
#include <iostream>

#include "io.hh"
#include "str.hh"
#include "conf.hh"
#include "FeatureGenerator.hh"
#include "Recipe.hh"
#include "PhonePool.hh"
#include "PhnReader.hh"
#include "SpeakerConfig.hh"
#include "HmmNetBaumWelch.hh"

int max_contexts;
int info;

conf::Config config;
Recipe recipe;
HmmSet model;
FeatureGenerator fea_gen;
FeatureGenerator model_fea_gen;
FeatureGenerator *mfea_gen; // Set to the correct FeatureGenerator object
SpeakerConfig speaker_config(fea_gen);

void
collect_phone_stats(PhnReader *phn_reader, PhonePool *pool)
{
  int f;
  PhnReader::Phn phn;

  while (phn_reader->next_phn_line(phn))
  {
    if (phn.state == -1)
      throw std::string("Context phone tying requires phn files with state numbers!");
    PhonePool::ContextPhoneContainer phone = pool->get_context_phone(
      phn.label[0], phn.state);
    for (f = phn.start; f < phn.end; f++)
    {
      FeatureVec feature = fea_gen.generate(f);
      if (fea_gen.eof())
        break; // EOF in FeatureGenerator
      phone.add_feature(1, feature);
    }
    if (f < phn.end) // EOF in FeatureGenerator
      return;
  }
}

void
hmmnet_collect_phone_stats(HmmNetBaumWelch *seg, PhonePool *pool)
{
  int i;

  while (seg->next_frame())
  {
    std::vector<HmmNetBaumWelch::ArcInfo> arc_info;
    seg->fill_arc_info(arc_info);
    FeatureVec feature = fea_gen.generate(seg->current_frame());
    if (fea_gen.eof())
      break; // EOF in FeatureGenerator

    for (i = 0; i < (int)arc_info.size(); i++)
    {
      int state = -1;
      if (strchr(arc_info[i].label.c_str(), '.') != NULL){
	state = atoi((const char*)(strchr(arc_info[i].label.c_str(),'.')+1));
	arc_info[i].label.erase(arc_info[i].label.find('.', 0), 2);
      }
      if (state < 0)
      {
        fprintf(stderr, "Warning: Invalid label %s, ignoring current file\n",
                arc_info[i].label.c_str());
        return;
      }
      PhonePool::ContextPhoneContainer phone = pool->get_context_phone(
        arc_info[i].label, state);
      phone.add_feature(arc_info[i].prob, feature);
    }
  }
}

void
save_basebind(const std::string &filename, PhonePool *pool)
{
  FILE *fp;

  // Save silence models
  if ((fp = fopen(filename.c_str(), "w")) == NULL)
  {
    fprintf(stderr, "Could not open file %s for writing.\n", filename.c_str());
    exit(1);
  }
  //fprintf(fp, "_ 1 0\n__ 3 1 2 3\n");

  pool->save_to_basebind(fp, 0, max_contexts);
  fclose(fp);
}

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

  try {
    config("usage: tie [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('c', "config=FILE", "arg must", "", "feature configuration")
      ('r', "recipe=FILE", "arg must", "", "recipe file")
      ('O', "ophn", "", "", "use output phns for training")
      ('H', "hmmnet", "", "", "use HMM networks for training")
      ('b', "base=BASENAME", "arg", "", "model files (required with --hmmnet)")
      ('C', "mconfig=FILE", "arg", "", "model configuration (optional)")
      ('u', "rule=FILE", "arg must", "", "rule set for triphone state tying")
      ('o', "out=FILE", "arg", "", "write output to HMM model with base name FILE")
      ('B', "basebind=FILE", "arg", "", "write output to basebind FILE")
      ('R', "raw-input", "", "", "raw audio input")
      ('\0', "count=INT", "arg", "100", "minimum feature count for state clusters")
      ('\0', "sgain=FLOAT", "arg", "0", "minimum loglikelihood gain in cluster splitting")
      ('\0', "mloss=FLOAT", "arg", "0", "cluster merging with maximum loglikelihood loss")
      ('\0', "context=INT", "arg", "1", "maximum number of contexts (default 1=triphones)")
      ('F', "fw-beam=FLOAT", "arg", "0", "Forward beam (for HMM networks)")
      ('W', "bw-beam=FLOAT", "arg", "0", "Backward beam (for HMM networks)")
      ('A', "ac-scale=FLOAT", "arg", "1", "Acoustic scaling (for HMM networks)")
      ('V', "vit", "", "", "Use Viterbi over HMM networks")
      ('S', "speakers=FILE", "arg", "", "speaker configuration file")
      ('i', "info=INT", "arg", "0", "info level")
      ;
    config.default_parse(argc, argv);

    info = config["info"].get_int();
    fea_gen.load_configuration(io::Stream(config["config"].get_str()));

    // Read recipe file
    recipe.read(io::Stream(config["recipe"].get_str()), 0, 0, false);

    if (!(config["out"].specified^config["basebind"].specified))
      throw std::string("Specify either --out or --basebind for output");

    if (config["mloss"].specified && config["kmeans"].specified)
      throw std::string("Define only either --mloss or --kmeans");

    phone_pool.set_clustering_parameters(config["count"].get_int(),
                                         config["sgain"].get_float(),
                                         config["mloss"].get_float());

    phone_pool.load_decision_tree_rules(io::Stream(config["rule"].get_str()));

    max_contexts = config["context"].get_int();

    if (config["speakers"].specified)
    {
      speaker_config.read_speaker_file(
        io::Stream(config["speakers"].get_str()));
    }

    // Initialize triphone tying
    phone_pool.set_dimension(fea_gen.dim());
    phone_pool.set_info(info);

    if (config["hmmnet"].specified)
    {
      if (config["base"].specified)
      {
        model.read_all(config["base"].get_str());
        if (config["mconfig"].specified)
        {
          model_fea_gen.load_configuration(
            io::Stream(config["mconfig"].get_str()));
          if (model_fea_gen.frame_rate() != fea_gen.frame_rate())
            throw str::fmt(256, "Frame rate of the model and the feature generator must match!\nModel frame rate is %.3f, feature generator frame rate is %3.f\n", model_fea_gen.frame_rate(), fea_gen.frame_rate());
          mfea_gen = &model_fea_gen;
        }
        else
          mfea_gen = &fea_gen; // Use the feature configuration
      }
      else
      {
        throw std::string("HMM model is required with HMM networks");
      }
      if (model.dim() != mfea_gen->dim()) {
        throw str::fmt(128,
                       "gaussian dimension is %d but feature dimension is %d",
                       model.dim(), mfea_gen->dim());
      }
    }

    for (int f = 0; f < (int)recipe.infos.size(); f++)
    {
      if (info > 0)
      {
        fprintf(stderr, "Processing file: %s",
                recipe.infos[f].audio_path.c_str());
        if (recipe.infos[f].start_time || recipe.infos[f].end_time)
          fprintf(stderr," (%.2f-%.2f)",recipe.infos[f].start_time,
                  recipe.infos[f].end_time);
        fprintf(stderr,"\n");
      }

      if (config["speakers"].specified)
      {
        speaker_config.set_speaker(recipe.infos[f].speaker_id);
        if (recipe.infos[f].utterance_id.size() > 0)
          speaker_config.set_utterance(recipe.infos[f].utterance_id);
      }

      if (config["hmmnet"].specified)
      {
        // Open files and configure
        HmmNetBaumWelch* lattice = recipe.infos[f].init_hmmnet_files(
          &model, false, mfea_gen, config["raw-input"].specified, NULL);
        lattice->set_pruning_thresholds(config["bw-beam"].get_float(),
                                        config["fw-beam"].get_float());
        if (config["ac-scale"].specified)
          lattice->set_acoustic_scaling(config["ac-scale"].get_float());
        if (config["vit"].specified)
          lattice->set_mode(HmmNetBaumWelch::MODE_VITERBI);

        if (mfea_gen != &fea_gen)
        {
          // Open the file for the actual feature generator
          fea_gen.open(recipe.infos[f].audio_path,
                       config["raw-input"].specified);
        }

        double orig_beam = lattice->get_backward_beam();
        int counter = 1;
        bool skip = false;
        while (!lattice->init_utterance_segmentation())
        {
          if (counter >= 5)
          {
            fprintf(stderr, "Could not run Baum-Welch for file %s\n",
                    recipe.infos[f].audio_path.c_str());
            fprintf(stderr, "The HMM network may be incorrect or initial beam too low.\n");
            skip = true;
            break;
          }
          fprintf(stderr,
                  "Warning: Backward phase failed, increasing beam to %.1f\n",
                  ++counter*orig_beam);
          lattice->set_pruning_thresholds(counter*orig_beam, 0);
        }
        if (!skip)
          hmmnet_collect_phone_stats(lattice, &phone_pool);
        if (mfea_gen != &fea_gen) // fea_gen is closed elsewhere
          mfea_gen->close();
        delete lattice;
      }
      else
      {
        PhnReader phn_reader(NULL);
        recipe.infos[f].init_phn_files(NULL, false, false,
                                       config["ophn"].specified, &fea_gen,
                                       config["raw-input"].specified,
                                       &phn_reader);
        phn_reader.set_collect_transition_probs(false);
        collect_phone_stats(&phn_reader, &phone_pool);
        phn_reader.close();
      }

      fea_gen.close();
    }

    phone_pool.finish_statistics();
    phone_pool.decision_tree_cluster_context_phones(max_contexts);
    if (config["mloss"].specified)
      phone_pool.merge_context_phones();

    if (config["out"].specified)
      phone_pool.save_model(config["out"].get_str(), max_contexts);
    else
      save_basebind(config["basebind"].get_str(), &phone_pool);
  }
  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }
  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }
}
<commit_msg>*** empty log message ***<commit_after>#include <fstream>
#include <string>
#include <iostream>

#include "io.hh"
#include "str.hh"
#include "conf.hh"
#include "FeatureGenerator.hh"
#include "Recipe.hh"
#include "PhonePool.hh"
#include "PhnReader.hh"
#include "SpeakerConfig.hh"
#include "HmmNetBaumWelch.hh"

int max_contexts;
int info;

conf::Config config;
Recipe recipe;
HmmSet model;
FeatureGenerator fea_gen;
FeatureGenerator model_fea_gen;
FeatureGenerator *mfea_gen; // Set to the correct FeatureGenerator object
SpeakerConfig speaker_config(fea_gen);

void
collect_phone_stats(PhnReader *phn_reader, PhonePool *pool)
{
  int f;
  PhnReader::Phn phn;

  while (phn_reader->next_phn_line(phn))
  {
    if (phn.state == -1)
      throw std::string("Context phone tying requires phn files with state numbers!");
    PhonePool::ContextPhoneContainer phone = pool->get_context_phone(
      phn.label[0], phn.state);
    for (f = phn.start; f < phn.end; f++)
    {
      FeatureVec feature = fea_gen.generate(f);
      if (fea_gen.eof())
        break; // EOF in FeatureGenerator
      phone.add_feature(1, feature);
    }
    if (f < phn.end) // EOF in FeatureGenerator
      return;
  }
}

void
hmmnet_collect_phone_stats(HmmNetBaumWelch *seg, PhonePool *pool)
{
  int i;

  while (seg->next_frame())
  {
    std::vector<HmmNetBaumWelch::ArcInfo> arc_info;
    seg->fill_arc_info(arc_info);
    FeatureVec feature = fea_gen.generate(seg->current_frame());
    if (fea_gen.eof())
      break; // EOF in FeatureGenerator

    for (i = 0; i < (int)arc_info.size(); i++)
    {
      int state = -1;
      if (strchr(arc_info[i].label.c_str(), '.') != NULL){
	state = atoi((const char*)(strchr(arc_info[i].label.c_str(),'.')+1));
	arc_info[i].label.erase(arc_info[i].label.find('.', 0), 2);
      }
      if (state < 0)
      {
        fprintf(stderr, "Warning: Invalid label %s, ignoring current file\n",
                arc_info[i].label.c_str());
        return;
      }
      PhonePool::ContextPhoneContainer phone = pool->get_context_phone(
        arc_info[i].label, state);
      phone.add_feature(arc_info[i].prob, feature);
    }
  }
}

void
save_basebind(const std::string &filename, PhonePool *pool)
{
  FILE *fp;

  // Save silence models
  if ((fp = fopen(filename.c_str(), "w")) == NULL)
  {
    fprintf(stderr, "Could not open file %s for writing.\n", filename.c_str());
    exit(1);
  }
  //fprintf(fp, "_ 1 0\n__ 3 1 2 3\n");

  pool->save_to_basebind(fp, 0, max_contexts);
  fclose(fp);
}

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

  try {
    config("usage: tie [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('c', "config=FILE", "arg must", "", "feature configuration")
      ('r', "recipe=FILE", "arg must", "", "recipe file")
      ('O', "ophn", "", "", "use output phns for training")
      ('H', "hmmnet", "", "", "use HMM networks for training")
      ('b', "base=BASENAME", "arg", "", "model files (required with --hmmnet)")
      ('C', "mconfig=FILE", "arg", "", "model configuration (optional)")
      ('u', "rule=FILE", "arg must", "", "rule set for triphone state tying")
      ('o', "out=FILE", "arg", "", "write output to HMM model with base name FILE")
      ('B', "basebind=FILE", "arg", "", "write output to basebind FILE")
      ('R', "raw-input", "", "", "raw audio input")
      ('\0', "count=INT", "arg", "100", "minimum feature count for state clusters")
      ('\0', "sgain=FLOAT", "arg", "0", "minimum loglikelihood gain in cluster splitting")
      ('\0', "mloss=FLOAT", "arg", "0", "cluster merging with maximum loglikelihood loss")
      ('\0', "context=INT", "arg", "1", "maximum number of contexts (default 1=triphones)")
      ('F', "fw-beam=FLOAT", "arg", "0", "Forward beam (for HMM networks)")
      ('W', "bw-beam=FLOAT", "arg", "0", "Backward beam (for HMM networks)")
      ('A', "ac-scale=FLOAT", "arg", "1", "Acoustic scaling (for HMM networks)")
      ('V', "vit", "", "", "Use Viterbi over HMM networks")
      ('S', "speakers=FILE", "arg", "", "speaker configuration file")
      ('i', "info=INT", "arg", "0", "info level")
      ;
    config.default_parse(argc, argv);

    info = config["info"].get_int();
    fea_gen.load_configuration(io::Stream(config["config"].get_str()));

    // Read recipe file
    recipe.read(io::Stream(config["recipe"].get_str()), 0, 0, false);

    if (!(config["out"].specified^config["basebind"].specified))
      throw std::string("Specify either --out or --basebind for output");

    phone_pool.set_clustering_parameters(config["count"].get_int(),
                                         config["sgain"].get_float(),
                                         config["mloss"].get_float());

    phone_pool.load_decision_tree_rules(io::Stream(config["rule"].get_str()));

    max_contexts = config["context"].get_int();

    if (config["speakers"].specified)
    {
      speaker_config.read_speaker_file(
        io::Stream(config["speakers"].get_str()));
    }

    // Initialize triphone tying
    phone_pool.set_dimension(fea_gen.dim());
    phone_pool.set_info(info);

    if (config["hmmnet"].specified)
    {
      if (config["base"].specified)
      {
        model.read_all(config["base"].get_str());
        if (config["mconfig"].specified)
        {
          model_fea_gen.load_configuration(
            io::Stream(config["mconfig"].get_str()));
          if (model_fea_gen.frame_rate() != fea_gen.frame_rate())
            throw str::fmt(256, "Frame rate of the model and the feature generator must match!\nModel frame rate is %.3f, feature generator frame rate is %3.f\n", model_fea_gen.frame_rate(), fea_gen.frame_rate());
          mfea_gen = &model_fea_gen;
        }
        else
          mfea_gen = &fea_gen; // Use the feature configuration
      }
      else
      {
        throw std::string("HMM model is required with HMM networks");
      }
      if (model.dim() != mfea_gen->dim()) {
        throw str::fmt(128,
                       "gaussian dimension is %d but feature dimension is %d",
                       model.dim(), mfea_gen->dim());
      }
    }

    for (int f = 0; f < (int)recipe.infos.size(); f++)
    {
      if (info > 0)
      {
        fprintf(stderr, "Processing file: %s",
                recipe.infos[f].audio_path.c_str());
        if (recipe.infos[f].start_time || recipe.infos[f].end_time)
          fprintf(stderr," (%.2f-%.2f)",recipe.infos[f].start_time,
                  recipe.infos[f].end_time);
        fprintf(stderr,"\n");
      }

      if (config["speakers"].specified)
      {
        speaker_config.set_speaker(recipe.infos[f].speaker_id);
        if (recipe.infos[f].utterance_id.size() > 0)
          speaker_config.set_utterance(recipe.infos[f].utterance_id);
      }

      if (config["hmmnet"].specified)
      {
        // Open files and configure
        HmmNetBaumWelch* lattice = recipe.infos[f].init_hmmnet_files(
          &model, false, mfea_gen, config["raw-input"].specified, NULL);
        lattice->set_pruning_thresholds(config["bw-beam"].get_float(),
                                        config["fw-beam"].get_float());
        if (config["ac-scale"].specified)
          lattice->set_acoustic_scaling(config["ac-scale"].get_float());
        if (config["vit"].specified)
          lattice->set_mode(HmmNetBaumWelch::MODE_VITERBI);

        if (mfea_gen != &fea_gen)
        {
          // Open the file for the actual feature generator
          fea_gen.open(recipe.infos[f].audio_path,
                       config["raw-input"].specified);
        }

        double orig_beam = lattice->get_backward_beam();
        int counter = 1;
        bool skip = false;
        while (!lattice->init_utterance_segmentation())
        {
          if (counter >= 5)
          {
            fprintf(stderr, "Could not run Baum-Welch for file %s\n",
                    recipe.infos[f].audio_path.c_str());
            fprintf(stderr, "The HMM network may be incorrect or initial beam too low.\n");
            skip = true;
            break;
          }
          fprintf(stderr,
                  "Warning: Backward phase failed, increasing beam to %.1f\n",
                  ++counter*orig_beam);
          lattice->set_pruning_thresholds(counter*orig_beam, 0);
        }
        if (!skip)
          hmmnet_collect_phone_stats(lattice, &phone_pool);
        if (mfea_gen != &fea_gen) // fea_gen is closed elsewhere
          mfea_gen->close();
        delete lattice;
      }
      else
      {
        PhnReader phn_reader(NULL);
        recipe.infos[f].init_phn_files(NULL, false, false,
                                       config["ophn"].specified, &fea_gen,
                                       config["raw-input"].specified,
                                       &phn_reader);
        phn_reader.set_collect_transition_probs(false);
        collect_phone_stats(&phn_reader, &phone_pool);
        phn_reader.close();
      }

      fea_gen.close();
    }

    phone_pool.finish_statistics();
    phone_pool.decision_tree_cluster_context_phones(max_contexts);
    if (config["mloss"].specified)
      phone_pool.merge_context_phones();

    if (config["out"].specified)
      phone_pool.save_model(config["out"].get_str(), max_contexts);
    else
      save_basebind(config["basebind"].get_str(), &phone_pool);
  }
  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }
  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }
}
<|endoftext|>


<commit_before>#include "type.h"

#include "ast.h"
#include "scope.h"
#include "token.h"

#include <cassert>

#include <algorithm>
#include <iostream>

/***************** Type *********************/

static MemPoolImp<VoidType>         voidTypePool;
static MemPoolImp<ArrayType>        arrayTypePool;
static MemPoolImp<FuncType>         funcTypePool;
static MemPoolImp<PointerType>      pointerTypePool;
static MemPoolImp<StructType>  structUnionTypePool;
static MemPoolImp<ArithmType>       arithmTypePool;

Type* Type::MayCast(Type* type)
{
  auto funcType = type->ToFunc();
  auto arrayType = type->ToArray();
  if (funcType) {
    return PointerType::New(funcType);
  } else if (arrayType) {
    auto ret = PointerType::New(arrayType->Derived());
    ret->SetQual(Q_CONST);
    return ret;
  }
  return type;
}

VoidType* VoidType::New()
{
  static auto voidType = new (voidTypePool.Alloc()) VoidType(&voidTypePool);
  return voidType;
}

ArithmType* ArithmType::New(int typeSpec) {
#define NEW_TYPE(tag) \
  new (arithmTypePool.Alloc()) ArithmType(&arithmTypePool, tag);
  static auto boolType    = NEW_TYPE(T_BOOL);
  static auto charType    = NEW_TYPE(T_CHAR);
  static auto ucharType   = NEW_TYPE(T_UNSIGNED | T_CHAR);
  static auto shortType   = NEW_TYPE(T_SHORT);
  static auto ushortType  = NEW_TYPE(T_UNSIGNED | T_SHORT);
  static auto intType     = NEW_TYPE(T_INT);
  static auto uintType    = NEW_TYPE(T_UNSIGNED | T_INT);
  static auto longType    = NEW_TYPE(T_LONG);
  static auto ulongType   = NEW_TYPE(T_UNSIGNED | T_LONG);
  static auto llongType   = NEW_TYPE(T_LLONG)
  static auto ullongType  = NEW_TYPE(T_UNSIGNED | T_LLONG);
  static auto floatType   = NEW_TYPE(T_FLOAT);
  static auto doubleType  = NEW_TYPE(T_DOUBLE);
  static auto ldoubleType = NEW_TYPE(T_LONG | T_DOUBLE);

  auto tag = ArithmType::Spec2Tag(typeSpec);
  switch (tag) {
  case T_BOOL: return boolType;
  case T_CHAR: return charType;
  case T_UNSIGNED | T_CHAR: return ucharType;
  case T_SHORT: return shortType;
  case T_UNSIGNED | T_SHORT: return ushortType;
  case T_INT: return intType;
  case T_UNSIGNED:
  case T_UNSIGNED | T_INT: return uintType;
  case T_LONG: return longType;
  case T_UNSIGNED | T_LONG: return ulongType;
  case T_LLONG: return llongType;
  case T_UNSIGNED | T_LLONG: return ullongType;
  case T_FLOAT: return floatType;
  case T_DOUBLE: return doubleType;
  case T_LONG | T_DOUBLE: return ldoubleType;
  default: Error("complex not supported yet");
  }
  return nullptr; // Make compiler happy

#undef NEW_TYPE
}

ArrayType* ArrayType::New(int len, Type* eleType)
{
  return new (arrayTypePool.Alloc())
      ArrayType(&arrayTypePool, len, eleType);
}

//static IntType* NewIntType();
FuncType* FuncType::New(Type* derived, int funcSpec,
    bool variadic, const ParamList& params) {
  return new (funcTypePool.Alloc())
      FuncType(&funcTypePool, derived, funcSpec, variadic, params);
}

PointerType* PointerType::New(Type* derived) {
  return new (pointerTypePool.Alloc())
      PointerType(&pointerTypePool, derived);
}

StructType* StructType::New(
    bool isStruct, bool hasTag, Scope* parent) {
  return new (structUnionTypePool.Alloc())
      StructType(&structUnionTypePool, isStruct, hasTag, parent);
}

/*
static EnumType* Type::NewEnumType() {
  // TODO(wgtdkp):
  assert(false);
  return nullptr;
}
*/

/*************** ArithmType *********************/
int ArithmType::Width() const {
  switch (tag_) {
  case T_BOOL: case T_CHAR: case T_UNSIGNED | T_CHAR:
    return 1;
  case T_SHORT: case T_UNSIGNED | T_SHORT:
    return _intWidth >> 1;
  case T_INT: case T_UNSIGNED: case T_UNSIGNED | T_INT:
    return _intWidth;
  case T_LONG: case T_UNSIGNED | T_LONG:
    return _intWidth << 1;
  case T_LLONG: case T_UNSIGNED | T_LLONG:
    return _intWidth << 1;
  case T_FLOAT:
    return _intWidth;
  case T_DOUBLE:
    return _intWidth << 1;
  case T_LONG | T_DOUBLE:
    return _intWidth << 1;
  case T_FLOAT | T_COMPLEX:
    return _intWidth << 1;
  case T_DOUBLE | T_COMPLEX:
    return _intWidth << 2;
  case T_LONG | T_DOUBLE | T_COMPLEX:
    return _intWidth << 2;
  default:
    assert(false);
  }

  return _intWidth; // Make compiler happy
}

int ArithmType::Rank() const
{
  switch (tag_) {
  case T_BOOL: return 0;
  case T_CHAR: case T_UNSIGNED | T_CHAR: return 1;
  case T_SHORT: case T_UNSIGNED | T_SHORT: return 2;
  case T_INT: case T_UNSIGNED: case T_UNSIGNED | T_INT: return 3;
  case T_LONG: case T_UNSIGNED | T_LONG: return 4;
  case T_LLONG: case T_UNSIGNED | T_LLONG: return 5;
  case T_FLOAT: return 6;
  case T_DOUBLE: return 7;
  case T_LONG | T_DOUBLE: return 8;
  default: Error("complex not supported yet");
  }
  return 0;
}

ArithmType* ArithmType::MaxType(ArithmType* lhs, ArithmType* rhs)
{
  if (lhs->IsInteger())
    lhs = ArithmType::IntegerPromote(lhs);
  if (rhs->IsInteger())
    rhs = ArithmType::IntegerPromote(rhs);
  auto ret = lhs->Rank() > rhs->Rank() ? lhs: rhs;
  if (lhs->Width() == rhs->Width() && (lhs->IsUnsigned() || rhs->IsUnsigned()))
    return ArithmType::New(T_UNSIGNED | ret->Tag());
  return ret;
}

int ArithmType::Spec2Tag(int spec) {
  spec &= ~T_SIGNED;
  if ((spec & T_SHORT) || (spec & T_LONG)
      || (spec & T_LLONG)) {
    spec &= ~T_INT;
  }
  return spec;
}

std::string ArithmType::Str() const
{
  std::string width = std::string(":") + std::to_string(Width());

  switch (tag_) {
  case T_BOOL:
    return "bool" + width;

  case T_CHAR:
    return "char" + width;

  case T_UNSIGNED | T_CHAR:
    return "unsigned char" + width;

  case T_SHORT:
    return "short" + width;

  case T_UNSIGNED | T_SHORT:
    return "unsigned short" + width;

  case T_INT:
    return "int" + width;

  case T_UNSIGNED:
    return "unsigned int" + width;

  case T_LONG:
    return "long" + width;

  case T_UNSIGNED | T_LONG:
    return "unsigned long" + width;

  case T_LLONG:
    return "long long" + width;

  case T_UNSIGNED | T_LLONG:
    return "unsigned long long" + width;

  case T_FLOAT:
    return "float" + width;

  case T_DOUBLE:
    return "double" + width;

  case T_LONG | T_DOUBLE:
    return "long double" + width;

  case T_FLOAT | T_COMPLEX:
    return "float complex" + width;

  case T_DOUBLE | T_COMPLEX:
    return "double complex" + width;

  case T_LONG | T_DOUBLE | T_COMPLEX:
    return "long double complex" + width;

  default:
    assert(false);
  }

  return "error"; // Make compiler happy
}

bool PointerType::Compatible(const Type& other) const
{
  // C11 6.7.6.1 [2]: pointer compatibility
  auto otherPointer = other.ToPointer();
  return otherPointer && derived_->Compatible(*otherPointer->derived_);
}

bool ArrayType::Compatible(const Type& other) const
{
  // C11 6.7.6.2 [6]: For two array type to be compatible,
  // the element types must be compatible, and have same length
  // if both specified.
  auto otherArray = other.ToArray();
  if (!otherArray) return false;
  if (!derived_->Compatible(*otherArray->derived_)) return false;
  // The lengths are both not specified
  if (!complete_ && !otherArray->complete_) return true;
  if (complete_ != otherArray->complete_) return false;
  return len_ == otherArray->len_;
}

bool FuncType::Compatible(const Type& other) const
{
  auto otherFunc = other.ToFunc();
  //the other type is not an function type
  if (!otherFunc) return false;
  //TODO: do we need to check the type of return value when deciding
  //compatibility of two function types ??
  if (!derived_->Compatible(*otherFunc->derived_))
    return false;
  if (params_.size() != otherFunc->params_.size())
    return false;

  auto thisIter = params_.begin();
  auto otherIter = otherFunc->params_.begin();
  while (thisIter != params_.end()) {
    if (!(*thisIter)->Type()->Compatible(*(*otherIter)->Type()))
      return false;
    ++thisIter;
    ++otherIter;
  }

  return true;
}

std::string FuncType::Str() const
{
  auto str = derived_->Str() + "(";
  auto iter = params_.begin();
  for (; iter != params_.end(); iter++) {
    str += (*iter)->Type()->Str() + ", ";
  }
  if (variadic_)
    str += "...";
  else if (params_.size())
    str.resize(str.size() - 2);

  return str + ")";
}

StructType::StructType(MemPool* pool, bool isStruct,
                       bool hasTag, Scope* parent)
    : Type(pool, false), isStruct_(isStruct), hasTag_(hasTag),
      memberMap_(new Scope(parent, S_BLOCK)), offset_(0), width_(0),
      // If a struct type has no member, it gets alignment of 1
      align_(1) {}

Object* StructType::GetMember(const std::string& member)
{
  auto ident = memberMap_->FindInCurScope(member);
  if (ident == nullptr)
    return nullptr;
  return ident->ToObject();
}

void StructType::CalcWidth()
{
  width_ = 0;
  auto iter = memberMap_->identMap_.begin();
  for (; iter != memberMap_->identMap_.end(); iter++) {
    width_ += iter->second->Type()->Width();
  }
}

bool StructType::Compatible(const Type& other) const {
  // TODO:
  return this == &other; // Pointer comparison
}

// TODO(wgtdkp): more detailed representation
std::string StructType::Str() const
{
  std::string str = isStruct_ ? "struct": "union";
  return str + ":" + std::to_string(width_);
}

// Remove useless unnamed bitfield members
// They are just for parsing
void StructType::Finalize()
{
  for (auto iter = members_.begin(); iter != members_.end();) {
    if ((*iter)->BitFieldWidth() && (*iter)->Anonymous()) {
      members_.erase(iter++);
    } else {
      ++iter;
    }
  }
}

void StructType::AddMember(Object* member)
{
  auto offset = MakeAlign(offset_, member->Align());
  member->SetOffset(offset);

  members_.push_back(member);
  memberMap_->Insert(member->Name(), member);

  align_ = std::max(align_, member->Align());

  if (isStruct_) {
    offset_ = offset + member->Type()->Width();
    width_ = MakeAlign(offset_, align_);
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, member->Type()->Width());
    width_ = MakeAlign(width_, align_);
  }
}

void StructType::AddBitField(Object* bitField, int offset)
{
  bitField->SetOffset(offset);
  members_.push_back(bitField);
  //auto name = bitField->Tok() ? bitField->Name(): AnonymousBitField();
  if (!bitField->Anonymous())
    memberMap_->Insert(bitField->Name(), bitField);

  auto bytes = MakeAlign(bitField->BitFieldEnd(), 8) / 8;
  //align_ = std::max(align_, bitField->Align());
  // Does not aligned, default is 1
  if (isStruct_) {
    offset_ = offset + bytes;
    width_ = MakeAlign(offset_, std::max(align_, bitField->Align()));
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, bitField->Type()->Width());
  }
}

// Move members of Anonymous struct/union to external struct/union
void StructType::MergeAnony(Object* anony)
{
  auto anonyType = anony->Type()->ToStruct();
  auto offset = MakeAlign(offset_, anony->Align());

  // Members in map are never anonymous
  for (auto& kv: *anonyType->memberMap_) {
    auto& name = kv.first;
    auto member = kv.second->ToObject();
    // Every member of anonymous struct/union
    //     are offseted by external struct/union
    member->SetOffset(offset + member->Offset());

    if (GetMember(name)) {
      Error(member, "duplicated member '%s'", name.c_str());
    }
    //members_.push_back(member);
    // Simplify anony struct's member searching
    memberMap_->Insert(name, member);
  }
  anony->SetOffset(offset);
  members_.push_back(anony);

  align_ = std::max(align_, anony->Align());
  if (isStruct_) {
    offset_ = offset + anonyType->Width();
    width_ = MakeAlign(offset_, align_);
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, anonyType->Width());
  }
}

<commit_msg>beautify code<commit_after>#include "type.h"

#include "ast.h"
#include "scope.h"
#include "token.h"

#include <cassert>

#include <algorithm>
#include <iostream>

/***************** Type *********************/

static MemPoolImp<VoidType>         voidTypePool;
static MemPoolImp<ArrayType>        arrayTypePool;
static MemPoolImp<FuncType>         funcTypePool;
static MemPoolImp<PointerType>      pointerTypePool;
static MemPoolImp<StructType>  structUnionTypePool;
static MemPoolImp<ArithmType>       arithmTypePool;

Type* Type::MayCast(Type* type)
{
  auto funcType = type->ToFunc();
  auto arrayType = type->ToArray();
  if (funcType) {
    return PointerType::New(funcType);
  } else if (arrayType) {
    auto ret = PointerType::New(arrayType->Derived());
    ret->SetQual(Q_CONST);
    return ret;
  }
  return type;
}

VoidType* VoidType::New()
{
  static auto voidType = new (voidTypePool.Alloc()) VoidType(&voidTypePool);
  return voidType;
}

ArithmType* ArithmType::New(int typeSpec) {
#define NEW_TYPE(tag) \
  new (arithmTypePool.Alloc()) ArithmType(&arithmTypePool, tag);
  static auto boolType    = NEW_TYPE(T_BOOL);
  static auto charType    = NEW_TYPE(T_CHAR);
  static auto ucharType   = NEW_TYPE(T_UNSIGNED | T_CHAR);
  static auto shortType   = NEW_TYPE(T_SHORT);
  static auto ushortType  = NEW_TYPE(T_UNSIGNED | T_SHORT);
  static auto intType     = NEW_TYPE(T_INT);
  static auto uintType    = NEW_TYPE(T_UNSIGNED | T_INT);
  static auto longType    = NEW_TYPE(T_LONG);
  static auto ulongType   = NEW_TYPE(T_UNSIGNED | T_LONG);
  static auto llongType   = NEW_TYPE(T_LLONG)
  static auto ullongType  = NEW_TYPE(T_UNSIGNED | T_LLONG);
  static auto floatType   = NEW_TYPE(T_FLOAT);
  static auto doubleType  = NEW_TYPE(T_DOUBLE);
  static auto ldoubleType = NEW_TYPE(T_LONG | T_DOUBLE);

  auto tag = ArithmType::Spec2Tag(typeSpec);
  switch (tag) {
  case T_BOOL: return boolType;
  case T_CHAR: return charType;
  case T_UNSIGNED | T_CHAR: return ucharType;
  case T_SHORT: return shortType;
  case T_UNSIGNED | T_SHORT: return ushortType;
  case T_INT: return intType;
  case T_UNSIGNED:
  case T_UNSIGNED | T_INT: return uintType;
  case T_LONG: return longType;
  case T_UNSIGNED | T_LONG: return ulongType;
  case T_LLONG: return llongType;
  case T_UNSIGNED | T_LLONG: return ullongType;
  case T_FLOAT: return floatType;
  case T_DOUBLE: return doubleType;
  case T_LONG | T_DOUBLE: return ldoubleType;
  default: Error("complex not supported yet");
  }
  return nullptr; // Make compiler happy

#undef NEW_TYPE
}

ArrayType* ArrayType::New(int len, Type* eleType)
{
  return new (arrayTypePool.Alloc())
      ArrayType(&arrayTypePool, len, eleType);
}

//static IntType* NewIntType();
FuncType* FuncType::New(Type* derived, int funcSpec,
    bool variadic, const ParamList& params)
{
  return new (funcTypePool.Alloc())
      FuncType(&funcTypePool, derived, funcSpec, variadic, params);
}

PointerType* PointerType::New(Type* derived)
{
  return new (pointerTypePool.Alloc())
      PointerType(&pointerTypePool, derived);
}

StructType* StructType::New(
    bool isStruct, bool hasTag, Scope* parent)
{
  return new (structUnionTypePool.Alloc())
      StructType(&structUnionTypePool, isStruct, hasTag, parent);
}

/*
static EnumType* Type::NewEnumType() {
  // TODO(wgtdkp):
  assert(false);
  return nullptr;
}
*/

/*************** ArithmType *********************/
int ArithmType::Width() const
{
  switch (tag_) {
  case T_BOOL: case T_CHAR: case T_UNSIGNED | T_CHAR:
    return 1;
  case T_SHORT: case T_UNSIGNED | T_SHORT:
    return _intWidth >> 1;
  case T_INT: case T_UNSIGNED: case T_UNSIGNED | T_INT:
    return _intWidth;
  case T_LONG: case T_UNSIGNED | T_LONG:
    return _intWidth << 1;
  case T_LLONG: case T_UNSIGNED | T_LLONG:
    return _intWidth << 1;
  case T_FLOAT:
    return _intWidth;
  case T_DOUBLE:
    return _intWidth << 1;
  case T_LONG | T_DOUBLE:
    return _intWidth << 1;
  case T_FLOAT | T_COMPLEX:
    return _intWidth << 1;
  case T_DOUBLE | T_COMPLEX:
    return _intWidth << 2;
  case T_LONG | T_DOUBLE | T_COMPLEX:
    return _intWidth << 2;
  default:
    assert(false);
  }

  return _intWidth; // Make compiler happy
}

int ArithmType::Rank() const
{
  switch (tag_) {
  case T_BOOL: return 0;
  case T_CHAR: case T_UNSIGNED | T_CHAR: return 1;
  case T_SHORT: case T_UNSIGNED | T_SHORT: return 2;
  case T_INT: case T_UNSIGNED: case T_UNSIGNED | T_INT: return 3;
  case T_LONG: case T_UNSIGNED | T_LONG: return 4;
  case T_LLONG: case T_UNSIGNED | T_LLONG: return 5;
  case T_FLOAT: return 6;
  case T_DOUBLE: return 7;
  case T_LONG | T_DOUBLE: return 8;
  default: Error("complex not supported yet");
  }
  return 0;
}

ArithmType* ArithmType::MaxType(ArithmType* lhs, ArithmType* rhs)
{
  if (lhs->IsInteger())
    lhs = ArithmType::IntegerPromote(lhs);
  if (rhs->IsInteger())
    rhs = ArithmType::IntegerPromote(rhs);
  auto ret = lhs->Rank() > rhs->Rank() ? lhs: rhs;
  if (lhs->Width() == rhs->Width() && (lhs->IsUnsigned() || rhs->IsUnsigned()))
    return ArithmType::New(T_UNSIGNED | ret->Tag());
  return ret;
}

int ArithmType::Spec2Tag(int spec)
{
  spec &= ~T_SIGNED;
  if ((spec & T_SHORT) || (spec & T_LONG)
      || (spec & T_LLONG)) {
    spec &= ~T_INT;
  }
  return spec;
}

std::string ArithmType::Str() const
{
  std::string width = std::string(":") + std::to_string(Width());

  switch (tag_) {
  case T_BOOL:
    return "bool" + width;

  case T_CHAR:
    return "char" + width;

  case T_UNSIGNED | T_CHAR:
    return "unsigned char" + width;

  case T_SHORT:
    return "short" + width;

  case T_UNSIGNED | T_SHORT:
    return "unsigned short" + width;

  case T_INT:
    return "int" + width;

  case T_UNSIGNED:
    return "unsigned int" + width;

  case T_LONG:
    return "long" + width;

  case T_UNSIGNED | T_LONG:
    return "unsigned long" + width;

  case T_LLONG:
    return "long long" + width;

  case T_UNSIGNED | T_LLONG:
    return "unsigned long long" + width;

  case T_FLOAT:
    return "float" + width;

  case T_DOUBLE:
    return "double" + width;

  case T_LONG | T_DOUBLE:
    return "long double" + width;

  case T_FLOAT | T_COMPLEX:
    return "float complex" + width;

  case T_DOUBLE | T_COMPLEX:
    return "double complex" + width;

  case T_LONG | T_DOUBLE | T_COMPLEX:
    return "long double complex" + width;

  default:
    assert(false);
  }

  return "error"; // Make compiler happy
}

bool PointerType::Compatible(const Type& other) const
{
  // C11 6.7.6.1 [2]: pointer compatibility
  auto otherPointer = other.ToPointer();
  return otherPointer && derived_->Compatible(*otherPointer->derived_);
}

bool ArrayType::Compatible(const Type& other) const
{
  // C11 6.7.6.2 [6]: For two array type to be compatible,
  // the element types must be compatible, and have same length
  // if both specified.
  auto otherArray = other.ToArray();
  if (!otherArray) return false;
  if (!derived_->Compatible(*otherArray->derived_)) return false;
  // The lengths are both not specified
  if (!complete_ && !otherArray->complete_) return true;
  if (complete_ != otherArray->complete_) return false;
  return len_ == otherArray->len_;
}

bool FuncType::Compatible(const Type& other) const
{
  auto otherFunc = other.ToFunc();
  //the other type is not an function type
  if (!otherFunc) return false;
  //TODO: do we need to check the type of return value when deciding
  //compatibility of two function types ??
  if (!derived_->Compatible(*otherFunc->derived_))
    return false;
  if (params_.size() != otherFunc->params_.size())
    return false;

  auto thisIter = params_.begin();
  auto otherIter = otherFunc->params_.begin();
  while (thisIter != params_.end()) {
    if (!(*thisIter)->Type()->Compatible(*(*otherIter)->Type()))
      return false;
    ++thisIter;
    ++otherIter;
  }

  return true;
}

std::string FuncType::Str() const
{
  auto str = derived_->Str() + "(";
  auto iter = params_.begin();
  for (; iter != params_.end(); iter++) {
    str += (*iter)->Type()->Str() + ", ";
  }
  if (variadic_)
    str += "...";
  else if (params_.size())
    str.resize(str.size() - 2);

  return str + ")";
}

StructType::StructType(MemPool* pool, bool isStruct,
                       bool hasTag, Scope* parent)
    : Type(pool, false), isStruct_(isStruct), hasTag_(hasTag),
      memberMap_(new Scope(parent, S_BLOCK)), offset_(0), width_(0),
      // If a struct type has no member, it gets alignment of 1
      align_(1) {}

Object* StructType::GetMember(const std::string& member)
{
  auto ident = memberMap_->FindInCurScope(member);
  if (ident == nullptr)
    return nullptr;
  return ident->ToObject();
}

void StructType::CalcWidth()
{
  width_ = 0;
  auto iter = memberMap_->identMap_.begin();
  for (; iter != memberMap_->identMap_.end(); iter++) {
    width_ += iter->second->Type()->Width();
  }
}

bool StructType::Compatible(const Type& other) const {
  // TODO:
  return this == &other; // Pointer comparison
}

// TODO(wgtdkp): more detailed representation
std::string StructType::Str() const
{
  std::string str = isStruct_ ? "struct": "union";
  return str + ":" + std::to_string(width_);
}

// Remove useless unnamed bitfield members
// They are just for parsing
void StructType::Finalize()
{
  for (auto iter = members_.begin(); iter != members_.end();) {
    if ((*iter)->BitFieldWidth() && (*iter)->Anonymous()) {
      members_.erase(iter++);
    } else {
      ++iter;
    }
  }
}

void StructType::AddMember(Object* member)
{
  auto offset = MakeAlign(offset_, member->Align());
  member->SetOffset(offset);

  members_.push_back(member);
  memberMap_->Insert(member->Name(), member);

  align_ = std::max(align_, member->Align());

  if (isStruct_) {
    offset_ = offset + member->Type()->Width();
    width_ = MakeAlign(offset_, align_);
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, member->Type()->Width());
    width_ = MakeAlign(width_, align_);
  }
}

void StructType::AddBitField(Object* bitField, int offset)
{
  bitField->SetOffset(offset);
  members_.push_back(bitField);
  //auto name = bitField->Tok() ? bitField->Name(): AnonymousBitField();
  if (!bitField->Anonymous())
    memberMap_->Insert(bitField->Name(), bitField);

  auto bytes = MakeAlign(bitField->BitFieldEnd(), 8) / 8;
  //align_ = std::max(align_, bitField->Align());
  // Does not aligned, default is 1
  if (isStruct_) {
    offset_ = offset + bytes;
    width_ = MakeAlign(offset_, std::max(align_, bitField->Align()));
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, bitField->Type()->Width());
  }
}

// Move members of Anonymous struct/union to external struct/union
void StructType::MergeAnony(Object* anony)
{
  auto anonyType = anony->Type()->ToStruct();
  auto offset = MakeAlign(offset_, anony->Align());

  // Members in map are never anonymous
  for (auto& kv: *anonyType->memberMap_) {
    auto& name = kv.first;
    auto member = kv.second->ToObject();
    // Every member of anonymous struct/union
    //     are offseted by external struct/union
    member->SetOffset(offset + member->Offset());

    if (GetMember(name)) {
      Error(member, "duplicated member '%s'", name.c_str());
    }
    //members_.push_back(member);
    // Simplify anony struct's member searching
    memberMap_->Insert(name, member);
  }
  anony->SetOffset(offset);
  members_.push_back(anony);

  align_ = std::max(align_, anony->Align());
  if (isStruct_) {
    offset_ = offset + anonyType->Width();
    width_ = MakeAlign(offset_, align_);
  } else {
    assert(offset_ == 0);
    width_ = std::max(width_, anonyType->Width());
  }
}

<|endoftext|>


<commit_before>#include <zmq.hpp>
#include <string>
#include <iostream>
#include <cstdlib>
#include <unistd.h>

static bool IsTrue(std::string s) { return s == "true" || s == "TRUE" || s == "1"; }

class Zink
{
    // Default configuration
    std::string endpoint = "tcp://*:13415";
    std::string public_key = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
    std::string secret_key = "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6";
    bool curve = false;
    bool print_messages = true;
    bool print_parts = false;
    bool print_compact = false;

    int pause_after = -1;
    int exit_after = -1;

    zmq::context_t &context;
    zmq::socket_t socket;
    size_t message_cnt = 0;

  public:
    Zink(zmq::context_t &context) : context(context), socket(context, ZMQ_SUB)
    {
        const char *env;
        if (env = std::getenv("ZINK_ENDPOINT"))
            endpoint = env;

        if (env = std::getenv("ZINK_CURVE"))
            curve = IsTrue(env);

        if (env = std::getenv("ZINK_SECRET_KEY"))
        {
            endpoint = env;
            curve = true;
        }

        if (env = std::getenv("ZINK_PRINT"))
        {
            if (std::string("PARTS") == env)
                print_parts = true;

            if (std::string("COMPACT") == env)
                print_compact = true;
        }

        if (env = std::getenv("ZINK_PAUSE_AFTER"))
            pause_after = std::stoul(env);

        if (env = std::getenv("ZINK_EXIT_AFTER"))
            exit_after = std::stoul(env);

        if (curve)
        {
            socket.setsockopt(ZMQ_CURVE_SECRETKEY, secret_key.c_str(), secret_key.length());
            int curve_server = 1;
            socket.setsockopt(ZMQ_CURVE_SERVER, &curve_server, sizeof(curve_server));
        }

        socket.bind(endpoint.c_str());
        socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    }

    void ReceiveMessages()
    {
        while (true)
        {
            if (exit_after != -1 && message_cnt >= exit_after)
            {
                std::cout << std::endl << "Exiting after " << message_cnt << " messages"
                          << std::endl;
                return;
            }

            if (pause_after != -1 && message_cnt >= pause_after)
            {
                std::cout << std::endl << "Pausing after " << message_cnt << " messages"
                          << std::endl;
                pause();
                return;
            }

            ReceiveMessage();
        }
    }

    void ReceiveMessage()
    {
        bool more = true;
        int parts_cnt = 0;
        while (more)
        {
            zmq::message_t message;
            auto rc = socket.recv(&message);
            if (rc)
            {
                parts_cnt++;
                std::string m(reinterpret_cast<const char *>(message.data()), message.size());
                if (print_parts)
                    std::cout << "PART " << parts_cnt << ": " << m << std::endl;
                more = message.more();
            }
        }

        message_cnt++;

        if (print_compact)
        {
            std::cout << "." << std::flush;
            if (message_cnt % 100 == 0)
                std::cout << std::endl << message_cnt << " " << std::flush;
        }
        else if (print_messages)
            std::cout << "Message " << message_cnt << " with " << parts_cnt
                      << (parts_cnt > 1 ? " parts" : " part") << std::endl;
    }
};

int main(int argc, char **argv)
{
    zmq::context_t context(1);

    Zink z(context);
    z.ReceiveMessages();
}
<commit_msg>Remove in-class initialization<commit_after>#include <zmq.hpp>
#include <string>
#include <iostream>
#include <cstdlib>
#include <unistd.h>

static bool IsTrue(std::string s) { return s == "true" || s == "TRUE" || s == "1"; }

class Zink
{
    // Default configuration
    std::string endpoint;
    std::string public_key;
    std::string secret_key;
    bool curve;
    bool print_messages;
    bool print_parts;
    bool print_compact;

    int pause_after;
    int exit_after;

    zmq::context_t &context;
    zmq::socket_t socket;
    size_t message_cnt = 0;

  public:
    Zink(zmq::context_t &context)
            : endpoint("tcp://*:13415"),
              public_key("rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7"),
              secret_key("JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6"),
              curve(false),
              print_messages(true),
              print_parts(false),
              print_compact(false),
              pause_after(-1),
              exit_after(-1),
              context(context),
              socket(context, ZMQ_SUB)
    {
        const char *env;
        if (env = std::getenv("ZINK_ENDPOINT"))
            endpoint = env;

        if (env = std::getenv("ZINK_CURVE"))
            curve = IsTrue(env);

        if (env = std::getenv("ZINK_SECRET_KEY"))
        {
            endpoint = env;
            curve = true;
        }

        if (env = std::getenv("ZINK_PRINT"))
        {
            if (std::string("PARTS") == env)
                print_parts = true;

            if (std::string("COMPACT") == env)
                print_compact = true;
        }

        if (env = std::getenv("ZINK_PAUSE_AFTER"))
            pause_after = std::stoul(env);

        if (env = std::getenv("ZINK_EXIT_AFTER"))
            exit_after = std::stoul(env);

        if (curve)
        {
            socket.setsockopt(ZMQ_CURVE_SECRETKEY, secret_key.c_str(), secret_key.length());
            int curve_server = 1;
            socket.setsockopt(ZMQ_CURVE_SERVER, &curve_server, sizeof(curve_server));
        }

        socket.bind(endpoint.c_str());
        socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
    }

    void ReceiveMessages()
    {
        while (true)
        {
            if (exit_after != -1 && message_cnt >= exit_after)
            {
                std::cout << std::endl << "Exiting after " << message_cnt << " messages"
                          << std::endl;
                return;
            }

            if (pause_after != -1 && message_cnt >= pause_after)
            {
                std::cout << std::endl << "Pausing after " << message_cnt << " messages"
                          << std::endl;
                pause();
                return;
            }

            ReceiveMessage();
        }
    }

    void ReceiveMessage()
    {
        bool more = true;
        int parts_cnt = 0;
        while (more)
        {
            zmq::message_t message;
            auto rc = socket.recv(&message);
            if (rc)
            {
                parts_cnt++;
                std::string m(reinterpret_cast<const char *>(message.data()), message.size());
                if (print_parts)
                    std::cout << "PART " << parts_cnt << ": " << m << std::endl;
                more = message.more();
            }
        }

        message_cnt++;

        if (print_compact)
        {
            std::cout << "." << std::flush;
            if (message_cnt % 100 == 0)
                std::cout << std::endl << message_cnt << " " << std::flush;
        }
        else if (print_messages)
            std::cout << "Message " << message_cnt << " with " << parts_cnt
                      << (parts_cnt > 1 ? " parts" : " part") << std::endl;
    }
};

int main(int argc, char **argv)
{
    zmq::context_t context(1);

    Zink z(context);
    z.ReceiveMessages();
}
<|endoftext|>


<commit_before>#include <string>

class Item
{

private:
	int itemsLeft
	double price;
	std::string description;
	std::string name;
	std::string size;
	std:string flavor;
	int quantity;

public:

	/*getters and setter
		methods declaration*/

	void setItemsLeft(int itemsLeft);
	int getItemsLeft();

	void setPrice(double price);
	double getPrice();

	void setDescription(std::string description);
	std::string getDescription();

	void setName(std::string name);
	std::string getName();

	void setSize(std::string size);
	std::string getSize();

	void setFlavor(std::String flavor);
	std::string getFlavor();

	void setQuantity(int quantity);
	int getQuantity();

	Item(); //default constructor declaration
};

Item::Item() //default constructor (set values using setters)
{
	this->itemsLeft = 100; //defaulted to 100 items left
	this->price = 1.00 //default price of $1
	this->description = "null"; /*all strings are initially set to null remember to change them if a food or drink item has one of these attributes.

															 ***ALL ITEMS SHOULD HAVE NAME AND DESCRIPTIONS***
															 */
	this->name = "null";
	this->size = "null";
	this->flavor = "null";
	this->quantity = 1; //defaulted to 1 item for the order
}

void setItemsLeft(int itemsLeft) //set items left
{
	this->itemsLeft = itemsLeft;
}

int getItemsLeft() //get items left
{
	return itemsLeft;
}

void setPrice(double price) //set price
{
	this->price = price;
}

double getPrice() //get price
{
	return price;
}

void setDescription(std::string description) //set description
{
	this->description = description;
}

std::string getDescription() //get description
{
	return description;
}

void setName(std::string name) //set name
{
	this->name = name;
}

std::string getName() //get name
{
	return name;
}

void setSize(std::string size) //set size
{
	this->size = size;
}

std::string getSize() //get size
{
	return size;
}

void setFlavor(std::string flavor) //set flavor
{
	this->flavor = flavor;
}

std::string getFlavor() //get flavor
{
	return flavor;
}

void setQuantity(int quantity) //set quantity
{
	this->quantity = quantity;
}

int getQuantity() //get quantity
{
	return quantity;
}
<commit_msg>Edited comments<commit_after>#include <string>

class Item
{

private:
	int itemsLeft
	double price;
	std::string description;
	std::string name;
	std::string size;
	std:string flavor;
	int quantity;

public:

	/*getters and setter
		methods declaration*/

	void setItemsLeft(int itemsLeft);
	int getItemsLeft();

	void setPrice(double price);
	double getPrice();

	void setDescription(std::string description);
	std::string getDescription();

	void setName(std::string name);
	std::string getName();

	void setSize(std::string size);
	std::string getSize();

	void setFlavor(std::String flavor);
	std::string getFlavor();

	void setQuantity(int quantity);
	int getQuantity();

	Item(); //default constructor declaration
};

Item::Item() //default constructor (set values using setters)
{
	this->itemsLeft = 100; //defaulted to 100 items left
	this->price = 1.00 //default price of $1
	this->description = "null"; /*all strings are initially set to null
	remember to change them if a food or drink item has one of these attributes.

 ***ALL ITEMS SHOULD HAVE NAME AND DESCRIPTIONS***
															 */
	this->name = "null";
	this->size = "null";
	this->flavor = "null";
	this->quantity = 1; //defaulted to 1 item for the order
}

void setItemsLeft(int itemsLeft) //set items left
{
	this->itemsLeft = itemsLeft;
}

int getItemsLeft() //get items left
{
	return itemsLeft;
}

void setPrice(double price) //set price
{
	this->price = price;
}

double getPrice() //get price
{
	return price;
}

void setDescription(std::string description) //set description
{
	this->description = description;
}

std::string getDescription() //get description
{
	return description;
}

void setName(std::string name) //set name
{
	this->name = name;
}

std::string getName() //get name
{
	return name;
}

void setSize(std::string size) //set size
{
	this->size = size;
}

std::string getSize() //get size
{
	return size;
}

void setFlavor(std::string flavor) //set flavor
{
	this->flavor = flavor;
}

std::string getFlavor() //get flavor
{
	return flavor;
}

void setQuantity(int quantity) //set quantity
{
	this->quantity = quantity;
}

int getQuantity() //get quantity
{
	return quantity;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <wiringPi.h>
#include <lcd.h>
#include <mcp23017.h>
using namespace std;

void instrumentChange(string, &string);
void octaveChange(string, string, &string);
void displayChange(string, string);
void initialization();

// Hardware powers on start up

int main()
{
   initialization();

   string currentInstrument;
   string currentOctave;

   bool instrumentButton;
   bool octaveButton;

   while (1) // Infinite loop
   {
      while (instrumentButton == 1) // While the instrument button is pressed...
      {
         if (currentInstrument == "piano")
         {
            instrumentChange("guitar", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
         else if (currentInstrument == "guitar")
         {
            instrumentChange("trumpet", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
         else
         {
            instrumentChange("piano", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
      }

      while (octaveButton == 1) // While the octave button is pressed...
      {
         if (currentOctave == "medium")
         {
            octaveChange("high", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
         else if (currentOctave == "high")
         {
            octaveChange("low", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
         else
         {
            octaveChange("medium", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
      }
   //}

   return 0; // Exit program
}

void initialization()
{
   //Initialization code

   // Default settings for piano
   instrumentChange("piano", currentInstrument);
   octaveChange("piano", "medium", currentOctave);

   // Default settings for display
   displayChange(currentInstrument, currentOctave);
}

void instrumentChange(string instrument, string &newInstrument) // Function for changing instruments
{
   if (instrument == "piano")
   {
      // Switch all button sound files to medium piano

      newInstrument = "piano";
   }
   else if (instrument == "guitar")
   {
      // Switch all button sound files to medium guitar

      newInstrument = "guitar";
   }
   else
   {
      // Switch all button sound files to medium trumpet

      newInstrument = "trumpet"
   }
}

void octaveChange(string instrument, string octave, string &newOctave) // Function for changing octaves
{
   if (instrument == "piano")
   {
      if (octave == "low")
      {
         // Switch all button sound files to low piano

         newOctave = "low";
      }
      else if (octave == "medium")
      {
         // Switch all button sound files to medium piano

         newOctave = "medium";
      }
      else
      {
         // Switch all button sound files to high piano

         newOctave = "high";
      }
   }
   else if (instrument == "guitar")
   {
      if (octave == "low")
      {
         // Switch all button sound files to low guitar

         newOctave = "low";
      }
      else if (octave == "medium")
      {
         // Switch all button sound files to medium guitar

         newOctave = "medium";
      }
      else
      {
         // Switch all button sound files to high guitar

         newOctave = "high";
      }
   }
   else
   {
      if (octave == "low")
      {
         // Switch all button sound files to low trumpet

         newOctave = "low";
      }
      else if (octave == "medium")
      {
         // Switch all button sound files to medium trumpet

         newOctave = "medium";
      }
      else
      {
         // Switch all button sound files to high trumpet

         newOctave = "high";
      }
   }

   void displayChange(string instrument, string octave)
   {
      // Displays instrument and octave
      cout << "Instrument: " << instrument << endl;
      cout << "Octave: " << octave;
   }
}<commit_msg>Implemented displayChange<commit_after>#include <iostream>
#include <string>
#include <wiringPi.h>
#include <lcd.h>
#include <mcp23017.h>
using namespace std;

void instrumentChange(string, &string);
void octaveChange(string, string, &string);
void displayChange(string, string);
void initialization();

// Hardware powers on start up

int main()
{

   string currentInstrument;
   string currentOctave;

   bool instrumentButton;
   bool octaveButton;

   while (1) // Infinite loop
   {
      while (instrumentButton == 1) // While the instrument button is pressed...
      {
         if (currentInstrument == "piano")
         {
            instrumentChange("guitar", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
         else if (currentInstrument == "guitar")
         {
            instrumentChange("trumpet", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
         else
         {
            instrumentChange("piano", currentInstrument);
            displayChange(currentInstrument, currentOctave);
         }
      }

      while (octaveButton == 1) // While the octave button is pressed...
      {
         if (currentOctave == "medium")
         {
            octaveChange("high", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
         else if (currentOctave == "high")
         {
            octaveChange("low", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
         else
         {
            octaveChange("medium", currentOctave);
            displayChange(currentInstrument, currentOctave);
         }
      }
   //}

   return 0; // Exit program
}

   void displayChange(Instrument currentInstrument, Octave currentOctave) // Function to change display values
   {
      // Change instrument on display
      string = Instrument;

      switch (currentInstrument)
      {
      case Piano :
         Instrument = "Piano";
         break;
      case Guitar :
         Instrument = "Guitar";
         break;
      case Trumpet :
         Instrument = "Trumpet";
         break;
      }

      lcdPosition(lcdHandle, 0, 0);
      lcdPuts(lcdHandle, "Instrument: " + Instrument);

      // Change octave on display
      string = Octave;

      switch (currentOctave)
      {
      case Low :
         Octave = "Low";
         break;
      case Medium :
         Octave = "Medium";
         break;
      case High :
         Octave = "High";
         break;
      }

      lcdPosition(lcdHandle, 0, 1);
      lcdPuts(lcdHandle, "Octave: " + Octave);
   }
}<|endoftext|>


<commit_before>/*
Provided to you by Emlid Ltd (c) 2014.
twitter.com/emlidtech || www.emlid.com || info@emlid.com

Example: Control servos connected to PCA9685 driver onboard of Navio shield for Raspberry Pi.

Connect servo to Navio's rc output and watch it work.
Output 1 on board is connected to PCA9685 channel 3, output 2 to channel 4 and so on.
To use full range of your servo correct SERVO_MIN and SERVO_MAX according to it's specification.

To run this example navigate to the directory containing it and run following commands:
make
./Servo
*/

#define NAVIO_RCOUTPUT_1 3
#define SERVO_MIN 1.250 /*mS*/
#define SERVO_MAX 1.750 /*mS*/

#include "Navio/PCA9685.h"

int main()
{
    PCA9685 pwm(RASPBERRY_PI_MODEL_B_I2C, PCA9685_DEFAULT_ADDRESS);
    // PCA9685 pwm(RASPBERRY_PI_MODEL_A_I2C, PCA9685_DEFAULT_ADDRESS);

    pwm.initialize();
    pwm.setFrequency(100);

    while (true) {
        pwm.setPWMmS(NAVIO_RCOUTPUT_1, SERVO_MIN);
        sleep(1);
        pwm.setPWMmS(NAVIO_RCOUTPUT_1, SERVO_MAX);
        sleep(1);
    }

    return 0;
}
<commit_msg>Updated servo example to set 50Hz frequency<commit_after>/*
Provided to you by Emlid Ltd (c) 2014.
twitter.com/emlidtech || www.emlid.com || info@emlid.com

Example: Control servos connected to PCA9685 driver onboard of Navio shield for Raspberry Pi.

Connect servo to Navio's rc output and watch it work.
Output 1 on board is connected to PCA9685 channel 3, output 2 to channel 4 and so on.
To use full range of your servo correct SERVO_MIN and SERVO_MAX according to it's specification.

To run this example navigate to the directory containing it and run following commands:
make
./Servo
*/

#define NAVIO_RCOUTPUT_1 3
#define SERVO_MIN 1.250 /*mS*/
#define SERVO_MAX 1.750 /*mS*/

#include "Navio/PCA9685.h"

int main()
{
    PCA9685 pwm(RASPBERRY_PI_MODEL_B_I2C, PCA9685_DEFAULT_ADDRESS);
    // PCA9685 pwm(RASPBERRY_PI_MODEL_A_I2C, PCA9685_DEFAULT_ADDRESS);

    pwm.initialize();
    pwm.setFrequency(50);

    while (true) {
        pwm.setPWMmS(NAVIO_RCOUTPUT_1, SERVO_MIN);
        sleep(1);
        pwm.setPWMmS(NAVIO_RCOUTPUT_1, SERVO_MAX);
        sleep(1);
    }

    return 0;
}
<|endoftext|>


<commit_before>//@author A0097630B
#include "stdafx.h"
#include <boost/lexical_cast.hpp>

#include "undo_query.h"

namespace {

/// The format for displaying an UNDO_QUERY
const std::wstring STRING_FORMAT(L"undo");

}  // namespace

namespace You {
namespace NLP {

std::wostream& operator<<(std::wostream& s, const UNDO_QUERY& q) {
	return s << STRING_FORMAT;
}

bool UNDO_QUERY::operator==(const UNDO_QUERY& rhs) const {
	// All undo queries are the same!
	return true;
}

std::wstring ToString(const UNDO_QUERY& q) {
	return boost::lexical_cast<std::wstring>(q);
}

}  // namespace NLP
}  // namespace You
<commit_msg>More warnings fixes.<commit_after>//@author A0097630B
#include "stdafx.h"
#include <boost/lexical_cast.hpp>

#include "undo_query.h"

namespace {

/// The format for displaying an UNDO_QUERY
const std::wstring STRING_FORMAT(L"undo");

}  // namespace

namespace You {
namespace NLP {

std::wostream& operator<<(std::wostream& s, const UNDO_QUERY& /*q*/) {
	return s << STRING_FORMAT;
}

bool UNDO_QUERY::operator==(const UNDO_QUERY& /*rhs*/) const {
	// All undo queries are the same!
	return true;
}

std::wstring ToString(const UNDO_QUERY& q) {
	return boost::lexical_cast<std::wstring>(q);
}

}  // namespace NLP
}  // namespace You
<|endoftext|>


<commit_before>/*=========================================================================

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkImage.h>

#include <irtkRegionFilter.h>

irtkRegionFilter::irtkRegionFilter()
{

}

irtkRegionFilter::~irtkRegionFilter(void)
{
}

Bool irtkRegionFilter::RequiresBuffering(void)
{
  return True;
}

const char *irtkRegionFilter::NameOfClass()
{
  return "irtkRegionFilter";
}

void irtkRegionFilter::Run()
{
  int i, j, k, l;
  double x1, y1, z1, x2, y2, z2;

  // Do the initial set up
  this->Initialize();

  if ((_i1 < 0) || (_i1 >= _i2) ||
      (_j1 < 0) || (_j1 >= _j2) ||
      (_k1 < 0) || (_k1 >= _k2) ||
      (_l1 < 0) || (_l1 >= _l2) ||
      (_i2 > _input->GetX()) || (_j2 > _input->GetX()) || (_k2 > _input->GetX()) || (_l2 > _input->GetX())) {
    cerr << "irtkRegionFilter::Run: Parameter out of range\n";
    exit(1);
  }

  // Initialize
  irtkImageAttributes attr = _input->GetImageAttributes();
  attr._x = _i2 - _i1;
  attr._y = _j2 - _j1;
  attr._z = _k2 - _k1;
  attr._t = _l2 - _l1;
  attr._xorigin = 0;
  attr._yorigin = 0;
  attr._zorigin = 0;
  _output->Initialize(attr);

  // Calculate position of first voxel in roi in original image
  x1 = _i1;
  y1 = _j1;
  z1 = _k1;
  _input->ImageToWorld(x1, y1, z1);

  // Calculate position of first voxel in roi in new image
  x2 = 0;
  y2 = 0;
  z2 = 0;
  _output->ImageToWorld(x2, y2, z2);

  // Shift origin of new image accordingly
  _output->PutOrigin(x1 - x2, y1 - y2, z1 - z2);

  // Copy region
  for (l = _l1; l < _l2; l++) {
    for (k = _k1; k < _k2; k++) {
      for (j = _j1; j < _j2; j++) {
        for (i = _i1; i < _i2; i++) {
          _output->PutAsDouble(i-_i1, j-_j1, k-_k1, l-_l1, _input->GetAsDouble(i, j, k, l));
        }
      }
    }
  }

  // Do the final cleaning up
  this->Finalize();
}
<commit_msg>Minor bug fix on bounds checking.<commit_after>/*=========================================================================

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkImage.h>

#include <irtkRegionFilter.h>

irtkRegionFilter::irtkRegionFilter()
{

}

irtkRegionFilter::~irtkRegionFilter(void)
{
}

Bool irtkRegionFilter::RequiresBuffering(void)
{
  return True;
}

const char *irtkRegionFilter::NameOfClass()
{
  return "irtkRegionFilter";
}

void irtkRegionFilter::Run()
{
  int i, j, k, l;
  double x1, y1, z1, x2, y2, z2;

  // Do the initial set up
  this->Initialize();

  if ((_i1 < 0) || (_i1 >= _i2) ||
      (_j1 < 0) || (_j1 >= _j2) ||
      (_k1 < 0) || (_k1 >= _k2) ||
      (_l1 < 0) || (_l1 >= _l2) ||
      (_i2 > _input->GetX()) || (_j2 > _input->GetY()) || (_k2 > _input->GetZ()) || (_l2 > _input->GetT())) {
    cerr << "irtkRegionFilter::Run: Parameter out of range\n";
    exit(1);
  }

  // Initialize
  irtkImageAttributes attr = _input->GetImageAttributes();
  attr._x = _i2 - _i1;
  attr._y = _j2 - _j1;
  attr._z = _k2 - _k1;
  attr._t = _l2 - _l1;
  attr._xorigin = 0;
  attr._yorigin = 0;
  attr._zorigin = 0;
  _output->Initialize(attr);

  // Calculate position of first voxel in roi in original image
  x1 = _i1;
  y1 = _j1;
  z1 = _k1;
  _input->ImageToWorld(x1, y1, z1);

  // Calculate position of first voxel in roi in new image
  x2 = 0;
  y2 = 0;
  z2 = 0;
  _output->ImageToWorld(x2, y2, z2);

  // Shift origin of new image accordingly
  _output->PutOrigin(x1 - x2, y1 - y2, z1 - z2);

  // Copy region
  for (l = _l1; l < _l2; l++) {
    for (k = _k1; k < _k2; k++) {
      for (j = _j1; j < _j2; j++) {
        for (i = _i1; i < _i2; i++) {
          _output->PutAsDouble(i-_i1, j-_j1, k-_k1, l-_l1, _input->GetAsDouble(i, j, k, l));
        }
      }
    }
  }

  // Do the final cleaning up
  this->Finalize();
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestStructuredGridConnectivity.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// .NAME TestStructuredGridConnectivity.cxx --Test vtkStructuredGridConnectivity
//
// .SECTION Description
//  A simple test for vtkStructuredGridConnectivity which constructs a uniform
//  grid with two partitions (pieces).

// C++ includes
#include <iostream>
#include <sstream>
#include <cassert>
#include <string>
#include <vector>

// VTK includes
#include "vtkDataSet.h"
#include "vtkUniformGrid.h"
#include "vtkMultiProcessController.h"
#include "vtkMultiPieceDataSet.h"
#include "vtkMPIController.h"
#include "vtkDataObject.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkInformation.h"
#include "vtkXMLImageDataWriter.h"
#include "vtkStructuredGridConnectivity.h"
#include "vtkStructuredNeighbor.h"
#include "vtkUnsignedCharArray.h"
#include "vtkIntArray.h"
#include "vtkMeshPropertyEncoder.h"
#include "vtkMeshProperty.h"
#include "vtkPointData.h"
#include "vtkCellData.h"

//------------------------------------------------------------------------------
// Description:
// Writes the grid to a file
void WriteGrid( vtkUniformGrid *grid, std::string prefix )
{
  assert( "pre: input grid is NULL" && (grid != NULL) );

  vtkXMLImageDataWriter *writer = vtkXMLImageDataWriter::New();

  std::ostringstream oss;
  oss << prefix << "." << writer->GetDefaultFileExtension();
  writer->SetFileName( oss.str().c_str() );
  writer->SetInput( grid );
  writer->Write();

  writer->Delete();
}

//------------------------------------------------------------------------------
// Description:
// Gets the grid for a given rank
vtkUniformGrid* GetGrid( const int rank, int globalExtent[6] )
{
  // Fix spacing at 0.5
  double h[3];
  h[0] = h[1] = h[2] = 0.5;

  // Fix dimensions to 10
  int dims[3];
  dims[0] = dims[1] = dims[2] = 10;

  // Fix global origin at (0.0, 0.0, 0.0)
  double globalOrigin[3];
  globalOrigin[0] = globalOrigin[1] = globalOrigin[2] = 0.0;

  // Setup the global extent for this grid instance
  for( int i=0; i < 3; ++i )
    {
    if( i == 0 )
      {
      globalExtent[i*2]   = rank*10;
      if( globalExtent[i*2] > 0)
        globalExtent[i*2]-= rank;

      globalExtent[i*2+1] = globalExtent[i*2]+10-1;
      }
    else
      {
      globalExtent[ i*2 ]   = 0;
      globalExtent[ i*2+1 ] = 9;
      }
    }

  // Compute local origin
  double localOrigin[3];
  localOrigin[0] = globalOrigin[0] + globalExtent[0]*h[0];
  localOrigin[1] = 0.0;
  localOrigin[2] = 0.0;

  // Setup uniform grid
  vtkUniformGrid *grid = vtkUniformGrid:: New();
  grid->SetOrigin( localOrigin );
  grid->SetDimensions( dims );
  grid->SetSpacing( h );

  return( grid );
}

//------------------------------------------------------------------------------
// Description:
// Generates a multipiece of uniform grids
vtkMultiPieceDataSet* GetDataSet( )
{
  vtkMultiPieceDataSet *mpds = vtkMultiPieceDataSet::New();

  // Setup the hole extent
  int wholeExtent[6];
  wholeExtent[0] = 0;                  // IMIN
  wholeExtent[1] = 18;                 // IMAX
  wholeExtent[2] = 0;                  // JMIN
  wholeExtent[3] = 9;                  // JMAX
  wholeExtent[4] = 0;                  // KMIN
  wholeExtent[5] = 9;                  // KMAX
  mpds->SetWholeExtent( wholeExtent );

  int ext1[6];
  int ext2[6];
  vtkUniformGrid *grid1 = GetGrid( 0, ext1 );
  vtkUniformGrid *grid2 = GetGrid( 1, ext2 );

  mpds->SetNumberOfPieces( 2 );
  mpds->SetPiece( 0, grid1 );
  mpds->GetMetaData( static_cast<unsigned int>(0) )->Set(
      vtkDataObject::PIECE_EXTENT(), ext1, 6 );
  mpds->SetPiece( 1, grid2 );
  mpds->GetMetaData( 1 )->Set( vtkDataObject::PIECE_EXTENT(),ext2, 6 );
  grid1->Delete();
  grid2->Delete();

  return( mpds );
}

//------------------------------------------------------------------------------
// Description:
// Program main
int main( int argc, char **argv )
{
  vtkMultiPieceDataSet *mpds = GetDataSet( );

  vtkStructuredGridConnectivity  *gridConnectivity =
      vtkStructuredGridConnectivity::New();
  gridConnectivity->SetNumberOfGrids( mpds->GetNumberOfPieces() );
  gridConnectivity->SetWholeExtent( mpds->GetWholeExtent() );

  int ext[6];
  std::ostringstream oss;
  for( unsigned int piece=0; piece < mpds->GetNumberOfPieces(); ++piece )
    {

    vtkUniformGrid *grid = vtkUniformGrid::SafeDownCast(mpds->GetPiece(piece ));

    if( grid != NULL )
      {
      oss.str( "" );
      oss << "GRID_" << piece;
      WriteGrid( grid, oss.str() );

      mpds->GetMetaData( piece )->Get( vtkDataObject::PIECE_EXTENT(),ext );

      gridConnectivity->RegisterGrid( piece, ext );
      }

    } // END for all pieces

  std::cout << "Creating ghost nodes...\n";
  std::cout.flush();
  gridConnectivity->ComputeNeighbors();
  std::cout << "[DONE]\n";
  std::cout.flush();

  // Calculate number of nodes
  int totalNumberOfNodes = 0;
  for( unsigned int piece=0; piece < mpds->GetNumberOfPieces(); ++piece )
    {
      vtkUniformGrid *grid =
          vtkUniformGrid::SafeDownCast(mpds->GetPiece(piece ));

      if( grid != NULL )
        {
        unsigned char *nodeProperty = new unsigned char[ grid->GetNumberOfPoints() ];
        unsigned char *cellProperty = new unsigned char[ grid->GetNumberOfCells() ];

        gridConnectivity->FillMeshPropertyArrays(
            piece, nodeProperty,cellProperty);

        vtkIntArray *flags = vtkIntArray::New();
        flags->SetName( "FLAGS" );
        flags->SetNumberOfComponents( 1 );
        flags->SetNumberOfTuples( grid->GetNumberOfPoints( ) );

        vtkIdType pIdx = 0;
        for( ; pIdx < grid->GetNumberOfPoints(); ++pIdx )
          {
          unsigned char p = nodeProperty[ pIdx ];
          if( vtkMeshPropertyEncoder::IsPropertySet(p,VTKNodeProperties::SHARED) )
            {
            flags->SetValue( pIdx, VTKNodeProperties::SHARED );
            }
          else if( vtkMeshPropertyEncoder::IsPropertySet(p,VTKNodeProperties::BOUNDARY) )
            {
            flags->SetValue(pIdx, VTKNodeProperties::BOUNDARY );
            }
          else
            {
            flags->SetValue(pIdx, VTKNodeProperties::INTERNAL );
            }

          } // END for all points

        grid->GetPointData()->AddArray( flags );
        flags->Delete();

        oss.str( "" );
        oss << "BLANKEDGRID_" << piece;
        WriteGrid( grid, oss.str() );

        }

    }// END for all pieces

  std::cout << "TOTAL NUMBER OF NODES: " << totalNumberOfNodes << std::endl;
  std::cout.flush();

  gridConnectivity->Delete();
  mpds->Delete();
  return 0;
}
<commit_msg>ENH: Apply logic to color nodes accordingly<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestStructuredGridConnectivity.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// .NAME TestStructuredGridConnectivity.cxx --Test vtkStructuredGridConnectivity
//
// .SECTION Description
//  A simple test for vtkStructuredGridConnectivity which constructs a uniform
//  grid with two partitions (pieces).

// C++ includes
#include <iostream>
#include <sstream>
#include <cassert>
#include <string>
#include <vector>

// VTK includes
#include "vtkDataSet.h"
#include "vtkUniformGrid.h"
#include "vtkMultiProcessController.h"
#include "vtkMultiPieceDataSet.h"
#include "vtkMPIController.h"
#include "vtkDataObject.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkInformation.h"
#include "vtkXMLImageDataWriter.h"
#include "vtkStructuredGridConnectivity.h"
#include "vtkStructuredNeighbor.h"
#include "vtkUnsignedCharArray.h"
#include "vtkIntArray.h"
#include "vtkMeshPropertyEncoder.h"
#include "vtkMeshProperty.h"
#include "vtkPointData.h"
#include "vtkCellData.h"

//------------------------------------------------------------------------------
// Description:
// Writes the grid to a file
void WriteGrid( vtkUniformGrid *grid, std::string prefix )
{
  assert( "pre: input grid is NULL" && (grid != NULL) );

  vtkXMLImageDataWriter *writer = vtkXMLImageDataWriter::New();

  std::ostringstream oss;
  oss << prefix << "." << writer->GetDefaultFileExtension();
  writer->SetFileName( oss.str().c_str() );
  writer->SetInput( grid );
  writer->Write();

  writer->Delete();
}

//------------------------------------------------------------------------------
// Description:
// Gets the grid for a given rank
vtkUniformGrid* GetGrid( const int rank, int globalExtent[6] )
{
  // Fix spacing at 0.5
  double h[3];
  h[0] = h[1] = h[2] = 0.5;

  // Fix dimensions to 10
  int dims[3];
  dims[0] = dims[1] = dims[2] = 10;

  // Fix global origin at (0.0, 0.0, 0.0)
  double globalOrigin[3];
  globalOrigin[0] = globalOrigin[1] = globalOrigin[2] = 0.0;

  // Setup the global extent for this grid instance
  for( int i=0; i < 3; ++i )
    {
    if( i == 0 )
      {
      globalExtent[i*2]   = rank*10;
      if( globalExtent[i*2] > 0)
        globalExtent[i*2]-= rank;

      globalExtent[i*2+1] = globalExtent[i*2]+10-1;
      }
    else
      {
      globalExtent[ i*2 ]   = 0;
      globalExtent[ i*2+1 ] = 9;
      }
    }

  // Compute local origin
  double localOrigin[3];
  localOrigin[0] = globalOrigin[0] + globalExtent[0]*h[0];
  localOrigin[1] = 0.0;
  localOrigin[2] = 0.0;

  // Setup uniform grid
  vtkUniformGrid *grid = vtkUniformGrid:: New();
  grid->SetOrigin( localOrigin );
  grid->SetDimensions( dims );
  grid->SetSpacing( h );

  return( grid );
}

//------------------------------------------------------------------------------
// Description:
// Generates a multipiece of uniform grids
vtkMultiPieceDataSet* GetDataSet( )
{
  vtkMultiPieceDataSet *mpds = vtkMultiPieceDataSet::New();

  // Setup the hole extent
  int wholeExtent[6];
  wholeExtent[0] = 0;                  // IMIN
  wholeExtent[1] = 18;                 // IMAX
  wholeExtent[2] = 0;                  // JMIN
  wholeExtent[3] = 9;                  // JMAX
  wholeExtent[4] = 0;                  // KMIN
  wholeExtent[5] = 9;                  // KMAX
  mpds->SetWholeExtent( wholeExtent );

  int ext1[6];
  int ext2[6];
  vtkUniformGrid *grid1 = GetGrid( 0, ext1 );
  vtkUniformGrid *grid2 = GetGrid( 1, ext2 );

  mpds->SetNumberOfPieces( 2 );
  mpds->SetPiece( 0, grid1 );
  mpds->GetMetaData( static_cast<unsigned int>(0) )->Set(
      vtkDataObject::PIECE_EXTENT(), ext1, 6 );
  mpds->SetPiece( 1, grid2 );
  mpds->GetMetaData( 1 )->Set( vtkDataObject::PIECE_EXTENT(),ext2, 6 );
  grid1->Delete();
  grid2->Delete();

  return( mpds );
}

//------------------------------------------------------------------------------
// Description:
// Program main
int main( int argc, char **argv )
{
  vtkMultiPieceDataSet *mpds = GetDataSet( );

  vtkStructuredGridConnectivity  *gridConnectivity =
      vtkStructuredGridConnectivity::New();
  gridConnectivity->SetNumberOfGrids( mpds->GetNumberOfPieces() );
  gridConnectivity->SetWholeExtent( mpds->GetWholeExtent() );

  int ext[6];
  std::ostringstream oss;
  for( unsigned int piece=0; piece < mpds->GetNumberOfPieces(); ++piece )
    {

    vtkUniformGrid *grid = vtkUniformGrid::SafeDownCast(mpds->GetPiece(piece ));

    if( grid != NULL )
      {
      oss.str( "" );
      oss << "GRID_" << piece;
      WriteGrid( grid, oss.str() );

      mpds->GetMetaData( piece )->Get( vtkDataObject::PIECE_EXTENT(),ext );

      gridConnectivity->RegisterGrid( piece, ext );
      }

    } // END for all pieces

  std::cout << "Creating ghost nodes...\n";
  std::cout.flush();
  gridConnectivity->ComputeNeighbors();
  std::cout << "[DONE]\n";
  std::cout.flush();

  // Calculate number of nodes
  int totalNumberOfNodes = 0;
  for( unsigned int piece=0; piece < mpds->GetNumberOfPieces(); ++piece )
    {
      vtkUniformGrid *grid =
          vtkUniformGrid::SafeDownCast(mpds->GetPiece(piece ));

      if( grid != NULL )
        {
        unsigned char *nodeProperty = new unsigned char[ grid->GetNumberOfPoints() ];
        unsigned char *cellProperty = new unsigned char[ grid->GetNumberOfCells() ];

        gridConnectivity->FillMeshPropertyArrays(
            piece, nodeProperty,cellProperty);

        vtkIntArray *flags = vtkIntArray::New();
        flags->SetName( "FLAGS" );
        flags->SetNumberOfComponents( 1 );
        flags->SetNumberOfTuples( grid->GetNumberOfPoints( ) );

        vtkIdType pIdx = 0;
        for( ; pIdx < grid->GetNumberOfPoints(); ++pIdx )
          {
          unsigned char p = nodeProperty[ pIdx ];
          if(!vtkMeshPropertyEncoder::IsPropertySet(p,VTKNodeProperties::IGNORE))
            {
            ++totalNumberOfNodes;
            if(vtkMeshPropertyEncoder::IsPropertySet(p,VTKNodeProperties::BOUNDARY))
              flags->SetValue( pIdx, 2 );
            else
              flags->SetValue( pIdx, 3);
            }
          else
            {
            flags->SetValue( pIdx, 1 );
            }

          } // END for all points

        grid->GetPointData()->AddArray( flags );
        flags->Delete();

        oss.str( "" );
        oss << "BLANKEDGRID_" << piece;
        WriteGrid( grid, oss.str() );

        }

    }// END for all pieces

  std::cout << "TOTAL NUMBER OF NODES: " << totalNumberOfNodes << std::endl;
  std::cout.flush();

  gridConnectivity->Delete();
  mpds->Delete();
  return 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Triangulator.h"

#include "Planet.h"

#include <EtRendering/GraphicsTypes/Frustum.h>
#include <EtRendering/SceneRendering/ShadedSceneRenderer.h>

namespace et {
namespace render {

void Triangulator::Init(Planet* const planet)
{
	m_Planet = planet;

	auto ico = math::GetIcosahedronPositions(m_Planet->GetRadius());
	auto indices = math::GetIcosahedronIndices();
	for (size_t i = 0; i < indices.size(); i+=3)
	{
		m_Icosahedron.push_back(Tri(ico[indices[i]], ico[indices[i+1]], ico[indices[i+2]], nullptr, 0));
	}

	Precalculate();

	//First geometry generation
	GenerateGeometry();
}

bool Triangulator::Update(mat4 const& transform, Camera const& camera)
{
	m_MaxLevel = 22;
	Precalculate();

	//Frustum update
	m_Frustum.SetCullTransform(transform);
	if (!m_LockFrustum)
	{
		m_Frustum.SetToCamera(camera);
	}

	m_Frustum.Update(Viewport::GetCurrentViewport());

	return true;
}

void Triangulator::Precalculate()
{
	//determine culling angle behind planet based on max height
	float cullingAngle = acosf(m_Planet->GetRadius()/(m_Planet->GetRadius()+m_Planet->GetMaxHeight()));
	//Dot Product LUT
	m_TriLevelDotLUT.clear();
	m_TriLevelDotLUT.push_back(0.5f+sinf(cullingAngle));
	float angle = acosf(0.5f);
	for (int32 i = 1; i <= m_MaxLevel; i++)
	{
		angle *= 0.5f;
		m_TriLevelDotLUT.push_back(sinf(angle+cullingAngle));
	}
	//height multipliers
	m_HeightMultLUT.clear();
	vec3 a = m_Icosahedron[0].a;
	vec3 b = m_Icosahedron[0].b;
	vec3 c = m_Icosahedron[0].c;
	vec3 center = (a + b + c) / 3.f;
	center = center * m_Planet->GetRadius() / math::length(center);//+maxHeight
	m_HeightMultLUT.push_back(1 / math::dot( math::normalize(a), math::normalize(center)));
	float normMaxHeight = m_Planet->GetMaxHeight() / m_Planet->GetRadius();
	for (int32 i = 1; i <= m_MaxLevel; i++)
	{
		vec3 A = b + ((c - b)*0.5f);
		vec3 B = c + ((a - c)*0.5f);
		c = a + ((b - a)*0.5f);
		a = A * m_Planet->GetRadius() / math::length(A);
		b = B * m_Planet->GetRadius() / math::length(B);
		c = c * m_Planet->GetRadius() / math::length(c);
		m_HeightMultLUT.push_back(1 / math::dot( math::normalize(a), math::normalize(center)) + normMaxHeight);
	}
}

void Triangulator::GenerateGeometry()
{
	//Precalculate Distance LUT
	//The distances generated should keep the triangles smaller than m_AllowedTriPx at any level
	//In future only recalculate on FOV or triangle density change
	m_DistanceLUT.clear();
	float sizeL = math::length(m_Icosahedron[0].a - m_Icosahedron[0].b);
	float frac = tanf((m_AllowedTriPx * math::radians(m_Frustum.GetFOV())) / Viewport::GetCurrentViewport()->GetDimensions().x);
	for (int32 level = 0; level < m_MaxLevel+5; level++)
	{
		m_DistanceLUT.push_back(sizeL / frac);
		sizeL *= 0.5f;
	}

	//Recursion start
	m_Positions.clear();

	for (auto t : m_Icosahedron)
	{
		RecursiveTriangle(t.a, t.b, t.c, t.level, true);
	}
}

TriNext Triangulator::SplitHeuristic(vec3 &a, vec3 &b, vec3 &c, int16 level, bool frustumCull)
{
	vec3 center = (a + b + c) / 3.f;
	//Perform backface culling
	float dotNV = math::dot( math::normalize(center), math::normalize(center - m_Frustum.GetPositionOS()));
	if (dotNV >= m_TriLevelDotLUT[level])
	{
		return TriNext::CULL;
	}

	//Perform Frustum culling
	if (frustumCull)
	{
		auto intersect = m_Frustum.ContainsTriVolume(a, b, c, m_HeightMultLUT[level]);
		//auto intersect = m_Frustum.ContainsTriangle(a, b, c);
		if (intersect == VolumeCheck::OUTSIDE) return TriNext::CULL;
		if (intersect == VolumeCheck::CONTAINS)//stop frustum culling -> all children are also inside the frustum
		{
			//check if new splits are allowed
			if (level >= m_MaxLevel)return TriNext::LEAF;
			//split according to distance
			float aDist = math::length(a - m_Frustum.GetPositionOS());
			float bDist = math::length(b - m_Frustum.GetPositionOS());
			float cDist = math::length(c - m_Frustum.GetPositionOS());
			if (std::fminf(aDist, std::fminf(bDist, cDist)) < m_DistanceLUT[level])return TriNext::SPLIT;
			return TriNext::LEAF;
		}
	}
	//check if new splits are allowed
	if (level >= m_MaxLevel)return TriNext::LEAF;
	//split according to distance
	float aDist = math::length(a - m_Frustum.GetPositionOS());
	float bDist = math::length(b - m_Frustum.GetPositionOS());
	float cDist = math::length(c - m_Frustum.GetPositionOS());
	if (std::fminf(aDist, std::fminf(bDist, cDist)) < m_DistanceLUT[level])return TriNext::SPLITCULL;
	return TriNext::LEAF;
}

void Triangulator::RecursiveTriangle(vec3 a, vec3 b, vec3 c, int16 level, bool frustumCull)
{
	TriNext next = SplitHeuristic(a, b, c, level, frustumCull);
	if (next == CULL) return;
	//check if subdivision is needed based on camera distance
	else if (next == SPLIT || next == SPLITCULL)
	{
		//find midpoints
		vec3 A = b + ((c - b)*0.5f);
		vec3 B = c + ((a - c)*0.5f);
		vec3 C = a + ((b - a)*0.5f);
		//make the distance from center larger according to planet radius
		A = A * m_Planet->GetRadius() / math::length(A);
		B = B * m_Planet->GetRadius() / math::length(B);
		C = C * m_Planet->GetRadius() / math::length(C);
		//Make 4 new triangles
		int16 nLevel = level + 1;
		RecursiveTriangle(a, B, C, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, b, C, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, B, c, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, B, C, nLevel, next == SPLITCULL);
	}
	else //put the triangle in the buffer
	{
		m_Positions.push_back(PatchInstance((BYTE)level, a, b-a, c-a));
	}
}

} // namespace render
} // namespace et
<commit_msg>Use computationally cheaper squared distance in SplitHeuristic.<commit_after>#include "stdafx.h"
#include "Triangulator.h"

#include "Planet.h"

#include <EtRendering/GraphicsTypes/Frustum.h>
#include <EtRendering/SceneRendering/ShadedSceneRenderer.h>

namespace et {
namespace render {

void Triangulator::Init(Planet* const planet)
{
	m_Planet = planet;

	auto ico = math::GetIcosahedronPositions(m_Planet->GetRadius());
	auto indices = math::GetIcosahedronIndices();
	for (size_t i = 0; i < indices.size(); i+=3)
	{
		m_Icosahedron.push_back(Tri(ico[indices[i]], ico[indices[i+1]], ico[indices[i+2]], nullptr, 0));
	}

	Precalculate();

	//First geometry generation
	GenerateGeometry();
}

bool Triangulator::Update(mat4 const& transform, Camera const& camera)
{
	m_MaxLevel = 22;
	Precalculate();

	//Frustum update
	m_Frustum.SetCullTransform(transform);
	if (!m_LockFrustum)
	{
		m_Frustum.SetToCamera(camera);
	}

	m_Frustum.Update(Viewport::GetCurrentViewport());

	return true;
}

void Triangulator::Precalculate()
{
	//determine culling angle behind planet based on max height
	float cullingAngle = acosf(m_Planet->GetRadius()/(m_Planet->GetRadius()+m_Planet->GetMaxHeight()));
	//Dot Product LUT
	m_TriLevelDotLUT.clear();
	m_TriLevelDotLUT.push_back(0.5f+sinf(cullingAngle));
	float angle = acosf(0.5f);
	for (int32 i = 1; i <= m_MaxLevel; i++)
	{
		angle *= 0.5f;
		m_TriLevelDotLUT.push_back(sinf(angle+cullingAngle));
	}
	//height multipliers
	m_HeightMultLUT.clear();
	vec3 a = m_Icosahedron[0].a;
	vec3 b = m_Icosahedron[0].b;
	vec3 c = m_Icosahedron[0].c;
	vec3 center = (a + b + c) / 3.f;
	center = center * m_Planet->GetRadius() / math::length(center);//+maxHeight
	m_HeightMultLUT.push_back(1 / math::dot( math::normalize(a), math::normalize(center)));
	float normMaxHeight = m_Planet->GetMaxHeight() / m_Planet->GetRadius();
	for (int32 i = 1; i <= m_MaxLevel; i++)
	{
		vec3 A = b + ((c - b)*0.5f);
		vec3 B = c + ((a - c)*0.5f);
		c = a + ((b - a)*0.5f);
		a = A * m_Planet->GetRadius() / math::length(A);
		b = B * m_Planet->GetRadius() / math::length(B);
		c = c * m_Planet->GetRadius() / math::length(c);
		m_HeightMultLUT.push_back(1 / math::dot( math::normalize(a), math::normalize(center)) + normMaxHeight);
	}
}

void Triangulator::GenerateGeometry()
{
	//Precalculate Distance LUT
	//The distances generated should keep the triangles smaller than m_AllowedTriPx at any level
	//In future only recalculate on FOV or triangle density change
	m_DistanceLUT.clear();
	float sizeL = math::length(m_Icosahedron[0].a - m_Icosahedron[0].b);
	float frac = tanf((m_AllowedTriPx * math::radians(m_Frustum.GetFOV())) / Viewport::GetCurrentViewport()->GetDimensions().x);
	for (int32 level = 0; level < m_MaxLevel+5; level++)
	{
		m_DistanceLUT.push_back(sizeL / frac);
		sizeL *= 0.5f;
	}

	//Recursion start
	m_Positions.clear();

	for (auto t : m_Icosahedron)
	{
		RecursiveTriangle(t.a, t.b, t.c, t.level, true);
	}
}

TriNext Triangulator::SplitHeuristic(vec3 &a, vec3 &b, vec3 &c, int16 level, bool frustumCull)
{
	vec3 center = (a + b + c) / 3.f;
	//Perform backface culling
	float dotNV = math::dot( math::normalize(center), math::normalize(center - m_Frustum.GetPositionOS()));
	if (dotNV >= m_TriLevelDotLUT[level])
	{
		return TriNext::CULL;
	}

	//Perform Frustum culling
	if (frustumCull)
	{
		auto intersect = m_Frustum.ContainsTriVolume(a, b, c, m_HeightMultLUT[level]);
		//auto intersect = m_Frustum.ContainsTriangle(a, b, c);
		if (intersect == VolumeCheck::OUTSIDE) return TriNext::CULL;
		if (intersect == VolumeCheck::CONTAINS)//stop frustum culling -> all children are also inside the frustum
		{
			//check if new splits are allowed
			if (level >= m_MaxLevel)return TriNext::LEAF;
			//split according to distance
			float aDistSq = math::distanceSquared(a, m_Frustum.GetPositionOS());
			float bDistSq = math::distanceSquared(b, m_Frustum.GetPositionOS());
			float cDistSq = math::distanceSquared(c, m_Frustum.GetPositionOS());
			float splitDistSq = m_DistanceLUT[level] * m_DistanceLUT[level];
			if (std::fminf(aDistSq, std::fminf(bDistSq, cDistSq)) < splitDistSq) return TriNext::SPLIT;
			return TriNext::LEAF;
		}
	}
	//check if new splits are allowed
	if (level >= m_MaxLevel)return TriNext::LEAF;
	//split according to distance
	float aDistSq = math::distanceSquared(a, m_Frustum.GetPositionOS());
	float bDistSq = math::distanceSquared(b, m_Frustum.GetPositionOS());
	float cDistSq = math::distanceSquared(c, m_Frustum.GetPositionOS());
	float splitDistSq = m_DistanceLUT[level] * m_DistanceLUT[level];
	if (std::fminf(aDistSq, std::fminf(bDistSq, cDistSq)) < splitDistSq) return TriNext::SPLITCULL;
	return TriNext::LEAF;
}

void Triangulator::RecursiveTriangle(vec3 a, vec3 b, vec3 c, int16 level, bool frustumCull)
{
	TriNext next = SplitHeuristic(a, b, c, level, frustumCull);
	if (next == CULL) return;
	//check if subdivision is needed based on camera distance
	else if (next == SPLIT || next == SPLITCULL)
	{
		//find midpoints
		vec3 A = b + ((c - b)*0.5f);
		vec3 B = c + ((a - c)*0.5f);
		vec3 C = a + ((b - a)*0.5f);
		//make the distance from center larger according to planet radius
		A = A * m_Planet->GetRadius() / math::length(A);
		B = B * m_Planet->GetRadius() / math::length(B);
		C = C * m_Planet->GetRadius() / math::length(C);
		//Make 4 new triangles
		int16 nLevel = level + 1;
		RecursiveTriangle(a, B, C, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, b, C, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, B, c, nLevel, next == SPLITCULL);//Winding is inverted
		RecursiveTriangle(A, B, C, nLevel, next == SPLITCULL);
	}
	else //put the triangle in the buffer
	{
		m_Positions.push_back(PatchInstance((BYTE)level, a, b-a, c-a));
	}
}

} // namespace render
} // namespace et
<|endoftext|>