Esempio n. 1
0
idx_t get_next_tileid(
  idx_t const previd,
  idx_t const * const tile_dims,
  idx_t const nmodes,
  idx_t const iter_mode,
  idx_t const mode_idx)
{
  idx_t maxid = 1;
  idx_t coords[MAX_NMODES];
  for(idx_t m=0; m < nmodes; ++m) {
    coords[m] = 0;
    maxid *= tile_dims[m];
  }

  if(previd == TILE_BEGIN) {
    coords[iter_mode] = mode_idx;
    return get_tile_id(tile_dims, nmodes, coords);
  }

  /* check for out of bounds */
  if(previd >= maxid) {
    return TILE_ERR;
  }

  /* convert previd to coords */
  fill_tile_coords(tile_dims, nmodes, previd, coords);

  /* overflowing this mode means TILE_END */
  idx_t const overmode = (iter_mode == 0) ? 1 : 0;

  /* increment least significant mode (unless we're iterating over it) and
   * propagate overflows */
  idx_t pmode = (iter_mode == nmodes-1) ? nmodes-2 : nmodes-1;
  ++coords[pmode];
  while(coords[pmode] == tile_dims[pmode]) {
    if(pmode == overmode) {
      return TILE_END;
    }

    /* overflow this one too and move on */
    coords[pmode] = 0;
    --pmode;

    /* we don't alter the mode we are iterating over */
    if(pmode == iter_mode) {
      /* XXX: checking for overmode should catch this */
      assert(pmode > 0);
      /* if we aren't at the end just skip over it */
      --pmode;
    }

    /* we're now at a valid mode, carry over previous overflow */
    ++coords[pmode];
  }

  return get_tile_id(tile_dims, nmodes, coords);
}
Esempio n. 2
0
void
EditorInputCenter::update_tile_selection() {
  Rectf select = tile_drag_rect();
  auto tiles = Editor::current()->tileselect.tiles.get();
  auto tilemap = dynamic_cast<TileMap*>(Editor::current()->layerselect.selected_tilemap);
  if ( !tilemap ) {
    return;
  }

  tiles->tiles.clear();
  tiles->width = select.get_width() + 1;
  tiles->height = select.get_height() + 1;

  int w = tilemap->get_width();
  int h = tilemap->get_height();
  for (int y = select.p1.y; y <= select.p2.y; y++) {
    for (int x = select.p1.x; x <= select.p2.x; x++) {
      if ( x < 0 || y < 0 || x >= w || y >= h) {
        tiles->tiles.push_back(0);
      } else {
        tiles->tiles.push_back(tilemap->get_tile_id(x, y));
      }
    }
  }
}
Esempio n. 3
0
/*
 * Use only 1 tile on a tensor with 'MAX_NMODES' modes. id should be 0.
 */
CTEST2(tile_traverse, get_tile_id_zero)
{
  __fill_arr(data->dims, MAX_NMODES, 1);
  __fill_arr(data->coords, MAX_NMODES, 0);

  /* one tile_traverse, id should always be 0 */
  ASSERT_EQUAL(0, get_tile_id(data->dims, MAX_NMODES, data->coords));
}
Esempio n. 4
0
File: tiled.c Progetto: rlofc/cage
/* Our tiles art are stored as spritemaps. Drawing
 * the tiles means drawing one of the frames in
 * one of the spritemaps we use for each layer.
 */
static void draw_tile(struct game* game,
                      struct sprite* tilemap,
                      enum map_layer layer_name,
                      struct tile_pos pos)
{
    draw_sprite_frame(tilemap,
                      TILE_SIZE * (pos.col) - game->camera.x,
                      TILE_SIZE * (pos.row) - game->camera.y,
                      get_tile_id(game->map_spec.data,
                                  game->layers[layer_name], pos) - 1);
}
Esempio n. 5
0
tilemap_component::tile_id_t tilemap_component::try_get_tile_id(unsigned x, unsigned y) const
{
  if(x < p_num_tiles.x() && y < p_num_tiles.y())
  {
    return get_tile_id(x, y);
  }
  else
  {
    return -1;
  }
}
Esempio n. 6
0
void
TileMap::change_all(uint32_t oldtile, uint32_t newtile)
{
  for (size_t x = 0; x < get_width(); x++) {
    for (size_t y = 0; y < get_height(); y++) {
      if (get_tile_id(x,y) != oldtile)
        continue;

      change(x,y,newtile);
    }
  }
}
Esempio n. 7
0
/*
 * Test get_tile_id on out of bounds values.
 */
CTEST2(tile_traverse, get_tile_id_oob)
{
  idx_t const nmodes = MAX_NMODES;
  for(idx_t m=0; m < nmodes; ++m) {
    data->dims[m] = m+1;
    data->coords[m] = m+1;
  }

  /* check out of bounds */
  ASSERT_EQUAL(TILE_ERR, get_tile_id(data->dims, nmodes, data->coords));

  for(idx_t m=0; m < nmodes; ++m) {
    data->coords[m] = m;
  }
  ASSERT_NOT_EQUAL(TILE_ERR, get_tile_id(data->dims, nmodes, data->coords));

  /* check each mode individually */
  for(idx_t m=0; m < nmodes; ++m) {
    ++data->coords[m];
    ASSERT_EQUAL(TILE_ERR, get_tile_id(data->dims, nmodes, data->coords));
    --data->coords[m];
  }
}
Esempio n. 8
0
CTEST2(tile_traverse, fill_tile_coords)
{
  idx_t const nmodes = 4;
  idx_t const nthreads = 4;
  idx_t ntiles = 1;

  for(idx_t m=0; m < nmodes; ++m) {
    data->dims[m] = nthreads;
    ntiles *= nthreads;
  }

  for(idx_t t=0; t < ntiles; ++t) {
    fill_tile_coords(data->dims, nmodes, t, data->coords);
    ASSERT_EQUAL(t, get_tile_id(data->dims, nmodes, data->coords));
  }
}
Esempio n. 9
0
/*
 * Test get_tile_id on a 3D problem with a prime number of threads.
 */
CTEST2(tile_traverse, get_tile_id_3d)
{
  idx_t const nmodes = 3;
  idx_t const nthreads = 7;

  __fill_arr(data->dims, nmodes, nthreads);

  idx_t id = 0;
  for(idx_t m1=0; m1 < nthreads; ++m1) {
    data->coords[0] = m1;
    for(idx_t m2=0; m2 < nthreads; ++m2) {
      data->coords[1] = m2;
      for(idx_t m3=0; m3 < nthreads; ++m3) {
        data->coords[2] = m3;
        ASSERT_EQUAL(id, get_tile_id(data->dims, nmodes, data->coords));
        ++id;
      }
    }
  }
}
Esempio n. 10
0
/*
 * Do a traversal of the space with non-uniform tile dimensions.
 */
CTEST2(tile_traverse, tile_weird_dim)
{
  idx_t const nmodes = 5;
  for(idx_t m=0; m < nmodes; ++m) {
    data->dims[m] = m+1;
  }

  for(idx_t m=0; m < nmodes; ++m) {
    /* empty tiles */
    __fill_arr(data->coords, nmodes, 0);

    /* the number of tiles that the traversal should go through */
    idx_t ntiles = 1;
    for(idx_t m2=0; m2 < nmodes; ++m2) {
      if(m2 != m) {
        ntiles *= data->dims[m2];
      }
    }

    /* now ensure every idx in the mode sees that it is the end */
    for(idx_t d=0; d < data->dims[m]; ++d) {
      idx_t startid = get_next_tileid(TILE_BEGIN, data->dims, nmodes, m, d);

      /* compute start id manually */
      data->coords[m] = d;
      idx_t const manual = get_tile_id(data->dims, nmodes, data->coords);
      ASSERT_EQUAL(manual, startid);

      /* Iterate over all tiles and also check last+1. Start from one because
       * TILE_BEGIN has already happened. */
      idx_t id = startid;
      for(idx_t t=1; t < ntiles; ++t) {
        id = get_next_tileid(id, data->dims, nmodes, m, d);
        ASSERT_NOT_EQUAL(startid, id);
        ASSERT_NOT_EQUAL(TILE_END, id);
      }
      id = get_next_tileid(id, data->dims, nmodes, m, d);
      ASSERT_EQUAL(TILE_END, id);
    }
  }
}
Esempio n. 11
0
/*
 * Test TILE_BEGIN functionality.
 */
CTEST2(tile_traverse, get_tile_id_begin)
{
  idx_t const nmodes = 6;
  idx_t const nthreads = 3;

  __fill_arr(data->dims, nmodes, nthreads);

  for(idx_t m=0; m < nmodes; ++m) {
    for(idx_t d=0; d < data->dims[m]; ++d) {
      /* get starting id */
      idx_t const b_id = get_next_tileid(TILE_BEGIN, data->dims, nmodes, m, d);

      /* now do it ourselves */
      __fill_arr(data->coords, nmodes, 0);
      data->coords[m] = d;
      idx_t const c_id = get_tile_id(data->dims, nmodes, data->coords);

      ASSERT_EQUAL(c_id, b_id);
    }
  }
}
Esempio n. 12
0
/*
 * Test TILE_END functionality.
 */
CTEST2(tile_traverse, get_tile_id_end)
{
  idx_t const nmodes = MAX_NMODES;
  idx_t const nthreads = 3;

  __fill_arr(data->dims, nmodes, nthreads);

  for(idx_t m=0; m < nmodes; ++m) {
    /* very last tile */
    __fill_arr(data->coords, nmodes, nthreads-1);

    /* now ensure every idx in the mode sees that it is the end */
    for(idx_t d=0; d < data->dims[m]; ++d) {
      /* now do it ourselves */
      data->coords[m] = d;
      idx_t const t_id = get_tile_id(data->dims, nmodes, data->coords);
      idx_t const b_id = get_next_tileid(t_id, data->dims, nmodes, m, d);
      ASSERT_EQUAL(TILE_END, b_id);
    }
  }
}
Esempio n. 13
0
/*
 * Test get_tile_id on a 3D problem with weird dimensions.
 */
CTEST2(tile_traverse, get_tile_id_weird_dim)
{
  idx_t const nmodes = 3;

  for(idx_t m=0; m < nmodes; ++m) {
    data->dims[m] = m+1;
  }

  idx_t id = 0;
  for(idx_t m1=0; m1 < data->dims[0]; ++m1) {
    data->coords[0] = m1;
    for(idx_t m2=0; m2 < data->dims[1]; ++m2) {
      data->coords[1] = m2;
      for(idx_t m3=0; m3 < data->dims[2]; ++m3) {
        data->coords[2] = m3;
        ASSERT_EQUAL(id, get_tile_id(data->dims, nmodes, data->coords));
        ++id;
      }
    }
  }
}
Esempio n. 14
0
void
SectorParser::parse_old_format(const ReaderMapping& reader)
{
  m_sector.name = "main";
  reader.get("gravity", m_sector.gravity);

  std::string backgroundimage;
  if (reader.get("background", backgroundimage) && (backgroundimage != "")) {
    if (backgroundimage == "arctis.png") backgroundimage = "arctis.jpg";
    if (backgroundimage == "arctis2.jpg") backgroundimage = "arctis.jpg";
    if (backgroundimage == "ocean.png") backgroundimage = "ocean.jpg";
    backgroundimage = "images/background/" + backgroundimage;
    if (!PHYSFS_exists(backgroundimage.c_str())) {
      log_warning << "Background image \"" << backgroundimage << "\" not found. Ignoring." << std::endl;
      backgroundimage = "";
    }
  }

  float bgspeed = .5;
  reader.get("bkgd_speed", bgspeed);
  bgspeed /= 100;

  Color bkgd_top, bkgd_bottom;
  int r = 0, g = 0, b = 128;
  reader.get("bkgd_red_top", r);
  reader.get("bkgd_green_top",  g);
  reader.get("bkgd_blue_top",  b);
  bkgd_top.red = static_cast<float> (r) / 255.0f;
  bkgd_top.green = static_cast<float> (g) / 255.0f;
  bkgd_top.blue = static_cast<float> (b) / 255.0f;

  reader.get("bkgd_red_bottom",  r);
  reader.get("bkgd_green_bottom", g);
  reader.get("bkgd_blue_bottom", b);
  bkgd_bottom.red = static_cast<float> (r) / 255.0f;
  bkgd_bottom.green = static_cast<float> (g) / 255.0f;
  bkgd_bottom.blue = static_cast<float> (b) / 255.0f;

  if(backgroundimage != "") {
    auto background = std::make_shared<Background>();
    background->set_image(backgroundimage, bgspeed);
    m_sector.add_object(background);
  } else {
    auto gradient = std::make_shared<Gradient>();
    gradient->set_gradient(bkgd_top, bkgd_bottom);
    m_sector.add_object(gradient);
  }

  std::string particlesystem;
  reader.get("particle_system", particlesystem);
  if(particlesystem == "clouds")
    m_sector.add_object(std::make_shared<CloudParticleSystem>());
  else if(particlesystem == "snow")
    m_sector.add_object(std::make_shared<SnowParticleSystem>());
  else if(particlesystem == "rain")
    m_sector.add_object(std::make_shared<RainParticleSystem>());

  Vector startpos(100, 170);
  reader.get("start_pos_x", startpos.x);
  reader.get("start_pos_y", startpos.y);

  auto spawn = std::make_shared<SpawnPoint>();
  spawn->pos = startpos;
  spawn->name = "main";
  m_sector.spawnpoints.push_back(spawn);

  m_sector.music = "chipdisko.ogg";
  // skip reading music filename. It's all .ogg now, anyway
  /*
    reader.get("music", music);
  */
  m_sector.music = "music/" + m_sector.music;

  int width = 30, height = 15;
  reader.get("width", width);
  reader.get("height", height);

  std::vector<unsigned int> tiles;
  if(reader.get("interactive-tm", tiles)
     || reader.get("tilemap", tiles)) {
    auto tileset = TileManager::current()->get_tileset(m_sector.level->get_tileset());
    auto tilemap = std::make_shared<TileMap>(tileset);
    tilemap->set(width, height, tiles, LAYER_TILES, true);

    // replace tile id 112 (old invisible tile) with 1311 (new invisible tile)
    for(size_t x=0; x < tilemap->get_width(); ++x) {
      for(size_t y=0; y < tilemap->get_height(); ++y) {
        uint32_t id = tilemap->get_tile_id(x, y);
        if(id == 112)
          tilemap->change(x, y, 1311);
      }
    }

    if (height < 19) tilemap->resize(width, 19);
    m_sector.add_object(tilemap);
  }

  if(reader.get("background-tm", tiles)) {
    auto tileset = TileManager::current()->get_tileset(m_sector.level->get_tileset());
    auto tilemap = std::make_shared<TileMap>(tileset);
    tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
    if (height < 19) tilemap->resize(width, 19);
    m_sector.add_object(tilemap);
  }

  if(reader.get("foreground-tm", tiles)) {
    auto tileset = TileManager::current()->get_tileset(m_sector.level->get_tileset());
    auto tilemap = std::make_shared<TileMap>(tileset);
    tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);

    // fill additional space in foreground with tiles of ID 2035 (lightmap/black)
    if (height < 19) tilemap->resize(width, 19, 2035);

    m_sector.add_object(tilemap);
  }

  // read reset-points (now spawn-points)
  ReaderMapping resetpoints;
  if(reader.get("reset-points", resetpoints)) {
    auto iter = resetpoints.get_iter();
    while(iter.next()) {
      if(iter.get_key() == "point") {
        Vector sp_pos;
        if(reader.get("x", sp_pos.x) && reader.get("y", sp_pos.y))
        {
          auto sp = std::make_shared<SpawnPoint>();
          sp->name = "main";
          sp->pos = sp_pos;
          m_sector.spawnpoints.push_back(sp);
        }
      } else {
        log_warning << "Unknown token '" << iter.get_key() << "' in reset-points." << std::endl;
      }
    }
  }

  // read objects
  ReaderCollection objects;
  if(reader.get("objects", objects)) {
    for(auto const& obj : objects.get_objects())
    {
      auto object = parse_object(obj.get_name(), obj.get_mapping());
      if(object) {
        m_sector.add_object(object);
      } else {
        log_warning << "Unknown object '" << obj.get_name() << "' in level." << std::endl;
      }
    }
  }

  // add a camera
  auto camera_ = std::make_shared<Camera>(&m_sector, "Camera");
  m_sector.add_object(camera_);

  m_sector.update_game_objects();

  if (m_sector.solid_tilemaps.empty()) {
    log_warning << "sector '" << m_sector.name << "' does not contain a solid tile layer." << std::endl;
  }

  fix_old_tiles();
  m_sector.update_game_objects();
}
Esempio n. 15
0
uint32_t
TileMap::get_tile_id_at(const Vector& pos) const
{
  Vector xy = (pos - offset) / 32;
  return get_tile_id(int(xy.x), int(xy.y));
}
Esempio n. 16
0
const Tile*
TileMap::get_tile(int x, int y) const
{
  uint32_t id = get_tile_id(x, y);
  return tileset->get(id);
}
Esempio n. 17
0
void
EditorInputCenter::fill() {

  auto tilemap = dynamic_cast<TileMap*>(Editor::current()->layerselect.selected_tilemap);
  if (! tilemap) {
    return;
  }

  // The tile that is going to be replaced:
  Uint32 replace_tile = tilemap->get_tile_id(hovered_tile.x, hovered_tile.y);

  if (Editor::current()->tileselect.tiles->pos(0, 0) == tilemap->get_tile_id(hovered_tile.x, hovered_tile.y)) {
    // Replacing by the same tiles shouldn't do anything.
    return;
  }

  std::vector<Vector> pos_stack;
  pos_stack.clear();
  pos_stack.push_back(hovered_tile);
  auto tiles = Editor::current()->tileselect.tiles.get();

  // Passing recursively trough all tiles to be replaced...
  while (pos_stack.size()) {

    if (pos_stack.size() > 1000000) {
      log_warning << "More than 1'000'000 tiles in stack to fill, STOP" << std::endl;
      return;
    }

    Vector pos = pos_stack[pos_stack.size() - 1];
    Vector tpos = pos - hovered_tile;

    // Tests for being inside tilemap:
    if ( pos.x < 0 || pos.y < 0 ||
         pos.x >= tilemap->get_width() || pos.y >= tilemap->get_height()) {
      pos_stack.pop_back();
      continue;
    }

    input_tile(pos, tiles->pos(tpos.x, tpos.y));
    Vector pos_;

    // Going left...
    pos_ = pos + Vector(-1, 0);
    if (pos_.x >= 0) {
      if (replace_tile == tilemap->get_tile_id(pos_.x, pos_.y) &&
          replace_tile != tiles->pos(tpos.x - 1, tpos.y)) {
        pos_stack.push_back( pos_ );
        continue;
      }
    }

    // Going right...
    pos_ = pos + Vector(1, 0);
    if (pos_.x < tilemap->get_width()) {
      if (replace_tile == tilemap->get_tile_id(pos_.x, pos_.y) &&
          replace_tile != tiles->pos(tpos.x + 1, tpos.y)) {
        pos_stack.push_back( pos_ );
        continue;
      }
    }

    // Going up...
    pos_ = pos + Vector(0, -1);
    if (pos_.y >= 0) {
      if (replace_tile == tilemap->get_tile_id(pos_.x, pos_.y) &&
          replace_tile != tiles->pos(tpos.x, tpos.y - 1)) {
        pos_stack.push_back( pos_ );
        continue;
      }
    }

    // Going down...
    pos_ = pos + Vector(0, 1);
    if (pos_.y < tilemap->get_height()) {
      if (replace_tile == tilemap->get_tile_id(pos_.x, pos_.y) &&
          replace_tile != tiles->pos(tpos.x, tpos.y + 1)) {
        pos_stack.push_back( pos_ );
        continue;
      }
    }

    // When tiles on each side are already filled or occupied by another tiles, it ends.
    pos_stack.pop_back();
  }
}
Esempio n. 18
0
idx_t * tt_densetile(
  sptensor_t * const tt,
  idx_t const * const tile_dims)
{
  timer_start(&timers[TIMER_TILE]);

  idx_t const nmodes = tt->nmodes;

  /*
   * Count tiles and compute their dimensions.
   */
  idx_t ntiles = 1;
  for(idx_t m=0; m < nmodes; ++m) {
    ntiles *= tile_dims[m];
  }
  /* the actual number of indices to place in each tile */
  idx_t tsizes[MAX_NMODES];
  for(idx_t m=0; m < nmodes; ++m) {
    tsizes[m] = SS_MAX(tt->dims[m] / tile_dims[m], 1);
  }

  /* We'll copy the newly tiled non-zeros into this one, then copy back */
  sptensor_t * newtt = tt_alloc(tt->nnz, tt->nmodes);

  /*
   * Count of non-zeros per tile. We use +1 because after a prefix sum, this
   * becomes a pointer into the non-zeros for each tile (e.g., csr->row_ptr).
   */
  idx_t * tcounts_global = splatt_malloc((ntiles+1) * sizeof(*tcounts_global));
  for(idx_t t=0; t < ntiles+1; ++t) {
    tcounts_global[t] = 0;
  }

  /* 
   * A matrix of thread-local counters.
   */
  int const nthreads = splatt_omp_get_max_threads();
  idx_t * * tcounts_thread = splatt_malloc(
      (nthreads+1) * sizeof(*tcounts_thread));

  /* After the prefix sum, the global counter will have the sum of all nnz in
   * each tile (across threads), and thus can be returned. */
  tcounts_thread[nthreads] = tcounts_global;

  /* partition the non-zeros */
  idx_t * thread_parts = partition_simple(tt->nnz, nthreads);

  #pragma omp parallel
  {
    int const tid = splatt_omp_get_thread_num();
    idx_t const nnz_start = thread_parts[tid];
    idx_t const nnz_end   = thread_parts[tid+1];

    /* allocate / initialize thread-local counters */
    tcounts_thread[tid] = splatt_malloc(ntiles * sizeof(**tcounts_thread));
    for(idx_t tile=0; tile < ntiles; ++tile) {
      tcounts_thread[tid][tile] = 0;
    }
    #pragma omp barrier

    /* offset by 1 to make prefix sum easy */
    idx_t * tcounts_local = tcounts_thread[tid+1];

    /* count tile sizes (in nnz) */
    idx_t coord[MAX_NMODES];
    for(idx_t x=nnz_start; x < nnz_end; ++x) {
      for(idx_t m=0; m < nmodes; ++m) {
        /* capping at dims-1 fixes overflow when dims don't divide evenly */
        coord[m] = SS_MIN(tt->ind[m][x] / tsizes[m], tile_dims[m]-1);
      }
      idx_t const id = get_tile_id(tile_dims, nmodes, coord);
      assert(id < ntiles);
      ++tcounts_local[id];
    }

    #pragma omp barrier
    #pragma omp single
    {
      /* prefix sum for each tile */
      for(idx_t tile=0; tile < ntiles; ++tile) {
        for(int thread=0; thread < nthreads; ++thread) {
          tcounts_thread[thread+1][tile] += tcounts_thread[thread][tile];
        }

        /* carry over to next tile */
        if(tile < (ntiles-1)) {
          tcounts_thread[0][tile+1] += tcounts_thread[nthreads][tile];
        }
      }
    } /* implied barrier */

    /* grab my starting indices now */
    tcounts_local = tcounts_thread[tid];

    /*
     * Rearrange old tensor into new tiled one.
     */
    for(idx_t x=nnz_start; x < nnz_end; ++x) {
      for(idx_t m=0; m < nmodes; ++m) {
        coord[m] = SS_MIN(tt->ind[m][x] / tsizes[m], tile_dims[m]-1);
      }
      /* offset by 1 to make prefix sum easy */
      idx_t const id = get_tile_id(tile_dims, nmodes, coord);
      assert(id < ntiles);

      idx_t const newidx = tcounts_local[id]++;
      newtt->vals[newidx] = tt->vals[x];
      for(idx_t m=0; m < nmodes; ++m) {
        newtt->ind[m][newidx] = tt->ind[m][x];
      }
    }

    splatt_free(tcounts_local);
  } /* end omp parallel */

  /* copy tiled data into old struct */
  par_memcpy(tt->vals, newtt->vals, tt->nnz * sizeof(*tt->vals));
  for(idx_t m=0; m < nmodes; ++m) {
    par_memcpy(tt->ind[m], newtt->ind[m], tt->nnz * sizeof(**tt->ind));
  }

  /* shift counts to the right by 1 to make proper pointer */
  memmove(tcounts_global+1, tcounts_global, ntiles * sizeof(*tcounts_global));
  tcounts_global[0] = 0;
  assert(tcounts_global[ntiles] == tt->nnz);

  tt_free(newtt);
  splatt_free(tcounts_thread);
  splatt_free(thread_parts);

  timer_stop(&timers[TIMER_TILE]);
  return tcounts_global;
}