<commit_before>#include <fstream>

#include "openmc/plot.h"
#include "openmc/constants.h"
#include "openmc/settings.h"
#include "openmc/error.h"
#include "openmc/particle.h"
#include "openmc/geometry.h"
#include "openmc/cell.h"
#include "openmc/material.h"
#include "openmc/string_functions.h"
#include "openmc/mesh.h"

namespace openmc {

const int RED   = 1;
const int GREEN = 2;
const int BLUE  = 3;

const int WHITE[3] = {255, 255, 255};
const int NULLRGB[3] = {0, 0, 0};

//===============================================================================
// RUN_PLOT controls the logic for making one or many plots
//===============================================================================

int openmc_plot_geometry() {
  int err;

  for (auto i : n_plots) {
    ObjectPlot* pl = plots[i];

    std::stringstream ss;
    ss << "Processing plot " << pl->id << ": "
       << pl->path_plot << "...";
      write_message(ss.str(), 5);

      if (PLOT_TYPE::SLICE == pl->type) {
        // create 2D image
        // create_ppm(pl);
        continue;
      } else if (PLOT_TYPE::VOXEL == pl->type) {
        // create voxel file for 3D viewing
        // create_voxel(pl);
        continue;
      }

  }

  return 0;
}

//===============================================================================
// CREATE_PPM creates an image based on user input from a plots.xml <plot>
// specification in the portable pixmap format (PPM)
//===============================================================================

void create_ppm(ObjectPlot* pl) {

  int width = pl->pixels[0];
  int height = pl->pixels[1];

  double in_pixel = (pl->width[0])/double(width);
  double out_pixel = (pl->width[1])/double(height);

  std::vector< std::vector< std::vector<int> > > data;

  data.resize(width);
  for (auto & i : data) {
    i.resize(height);
    for (auto & j : i) {
      j.resize(3);
    }
  }

  int in_i, out_i;
  double xyz[3];
  if (PLOT_BASIS::XY == pl->basis) {
    in_i = 0;
    out_i = 1;
    xyz[0] = pl->origin[0] - pl->width[0] / TWO;
    xyz[1] = pl->origin[1] + pl->width[1] / TWO;
    xyz[2] = pl->origin[2];
  } else if (PLOT_BASIS::XZ == pl->basis) {
    in_i = 0;
    out_i = 2;
    xyz[0] = pl->origin[0] - pl->width[0] / TWO;
    xyz[1] = pl->origin[1];
    xyz[2] = pl->origin[2] + pl->width[1] / TWO;
  } else if (PLOT_BASIS::YZ == pl->basis) {
    in_i = 1;
    out_i = 2;
    xyz[0] = pl->origin[0];
    xyz[1] = pl->origin[1] - pl->width[0] / TWO;
    xyz[2] = pl->origin[2] + pl->width[1] / TWO;
  }

  double dir[3] = {HALF, HALF, HALF};
  Particle *p = new Particle();
  p->initialize();
  std::copy(xyz, xyz+3, p->coord[0].xyz);
  std::copy(dir, dir+3, p->coord[0].uvw);
  p->coord[0].universe = openmc_root_universe;

  // local variables
  int rgb[3];
  int id;
  for (int y = 0; y < height; y++) {
    p->coord[0].xyz[out_i] = xyz[out_i] - out_pixel*(y);
    for (int x = 0; x < width; x++) {
      p->coord[0].xyz[in_i] = xyz[in_i] + in_pixel*(x);
      position_rgb(p, pl, rgb, id);
      data[x][y][0] = rgb[0];
      data[x][y][1] = rgb[1];
      data[x][y][2] = rgb[2];
    }
  }

  if (pl->index_meshlines_mesh >= 0) { draw_mesh_lines(pl, data); }

  output_ppm(pl, data);

}

//===============================================================================
// POSITION_RGB computes the red/green/blue values for a given plot with the
// current particle's position
//===============================================================================

void position_rgb(Particle* p, ObjectPlot* pl, int rgb[3], int &id) {
  bool found_cell;

  p->n_coord = 1;

  found_cell = find_cell(p, 0);

  int j = p->n_coord - 1;

  if (settings::check_overlaps) { check_cell_overlap(p); }

  // Set coordinate level if specified
  if (pl->level >= 0) {j = pl->level + 1;}

  Cell* c;

  if (!found_cell) {
    // If no cell, revert to default color
    std::copy(pl->not_found.rgb,
              pl->not_found.rgb + 3,
              rgb);
    id = -1;
  } else {
    if (PLOT_COLOR_BY::MATS == pl->color_by) {
      // Assign color based on material
      c = cells[p->coord[j].cell];
      if (c->type_ == FILL_UNIVERSE) {
        // If we stopped on a middle universe level, treat as if not found
        std::copy(pl->not_found.rgb,
                  pl->not_found.rgb + 3,
                  rgb);
        id = -1;
      } else if (p->material == MATERIAL_VOID) {
        // By default, color void cells white
        std::copy(WHITE, WHITE+3, rgb);
        id = -1;
      } else {
        std::copy(pl->colors[p->material - 1].rgb,
                  pl->colors[p->material - 1].rgb + 3,
                  rgb);
        id = materials[p->material - 1]->id;
      }

    } else if (PLOT_COLOR_BY::CELLS == pl->color_by) {
      // Assign color based on cell
      std::copy(pl->colors[p->coord[j].cell].rgb,
                pl->colors[p->coord[j].cell].rgb + 3,
                rgb);
      id = cells[p->coord[j].cell]->id_;
    } else {
      std::copy(NULLRGB, NULLRGB+3, rgb);
      id = -1;
    }

  } // endif found_cell
}

//===============================================================================
// OUTPUT_PPM writes out a previously generated image to a PPM file
//===============================================================================

  void output_ppm(ObjectPlot* pl,
                  const std::vector< std::vector< std::vector<int> > > &data)
{

  // Open PPM file for writing
  std::string fname = std::string(pl->path_plot);
  fname = strtrim(fname);
  std::ofstream of;

  of.open(fname);

  // Write header
  of << "P6" << std::endl;
  of << pl->pixels[0] << " " << pl->pixels[1] << std::endl;
  of << "255" << std::endl;
  of.close();

  of.open(fname, std::ios::binary | std::ios::app);
  // Write color for each pixel
  for (int y = 0; y < pl->pixels[1]; y++) {
    for (int x = 0; x < pl->pixels[0]; x++) {
      std::vector<int> rgb = data[x][y];
      of.write((char*)&rgb[0], 1);
      of.write((char*)&rgb[1], 1);
      of.write((char*)&rgb[2], 1);
    }
  }
  // Close file
  of.close();
}

//===============================================================================
// DRAW_MESH_LINES draws mesh line boundaries on an image
//===============================================================================

void draw_mesh_lines(ObjectPlot *pl,
                     std::vector< std::vector< std::vector<int> > > &data) {

  std::vector<int> rgb; rgb.resize(3);
  rgb[0] = pl->meshlines_color.rgb[0];
  rgb[1] = pl->meshlines_color.rgb[1];
  rgb[2] = pl->meshlines_color.rgb[2];

  int outer, inner;
  switch(pl->basis){
  case PLOT_BASIS::XY :
    outer = 0;
    inner = 1;
    break;
  case PLOT_BASIS::XZ :
    outer = 0;
    inner = 2;
    break;
  case PLOT_BASIS::YZ :
    outer = 1;
    inner = 2;
    break;
  }

  double xyz_ll_plot[3], xyz_ur_plot[3];
  std::copy((double*)&pl->origin, (double*)&pl->origin + 3, xyz_ll_plot);
  std::copy((double*)&pl->origin, (double*)&pl->origin + 3, xyz_ur_plot);

  xyz_ll_plot[outer] = pl->origin[outer] - pl->width[0] / TWO;
  xyz_ll_plot[inner] = pl->origin[inner] - pl->width[1] / TWO;
  xyz_ur_plot[outer] = pl->origin[outer] + pl->width[0] / TWO;
  xyz_ur_plot[inner] = pl->origin[inner] + pl->width[1] / TWO;

  int width[3];
  width[0] = xyz_ur_plot[0] - xyz_ll_plot[0];
  width[1] = xyz_ur_plot[1] - xyz_ll_plot[1];
  width[2] = xyz_ur_plot[2] - xyz_ll_plot[2];

  auto &m = meshes[pl->index_meshlines_mesh];

  int ijk_ll[3], ijk_ur[3];
  bool in_mesh;
  m->get_indices(Position(xyz_ll_plot), &(ijk_ll[0]), &in_mesh);
  m->get_indices(Position(xyz_ur_plot), &(ijk_ur[0]), &in_mesh);

  double frac;
  int outrange[3], inrange[3];
  double xyz_ll[3], xyz_ur[3];
  // sweep through all meshbins on this plane and draw borders
  for (int i = ijk_ll[outer]; i < ijk_ur[outer]; i++) {
    for (int j = ijk_ll[inner]; j < ijk_ur[inner]; j++) {
      // check if we're in the mesh for this ijk
      if (i > 0 && i <= m->shape_[outer] && j >0 && j <= m->shape_[inner] ) {

        // get xyz's of lower left and upper right of this mesh cell
        xyz_ll[outer] = m->lower_left_[outer] + m->width_[outer] * (i - 1);
        xyz_ll[inner] = m->lower_left_[inner] + m->width_[inner] * (j - 1);
        xyz_ur[outer] = m->lower_left_[outer] + m->width_[outer] * i;
        xyz_ur[inner] = m->lower_left_[inner] + m->width_[inner] * j;

        // map the xyz ranges to pixel ranges
        frac = (xyz_ll[outer] - xyz_ll_plot[outer]) / width[outer];
        outrange[0] = int(frac * double(pl->pixels[0]));
        frac = (xyz_ur[outer] - xyz_ll_plot[outer]) / width[outer];
        outrange[1] = int(frac * double(pl->pixels[0]));

        frac = (xyz_ur[inner] - xyz_ll_plot[inner]) / width[inner];
        inrange[0] = int((ONE - frac) * (double)pl->pixels[1]);
        frac = (xyz_ll[inner] - xyz_ll_plot[inner]) / width[inner];
        inrange[1] = int((ONE - frac) * (double)pl->pixels[1]);

        // draw lines
        for (int out_ = outrange[0]; out_ < outrange[1]; out_++) {
          for (int plus = 0; plus <= pl->meshlines_width; plus++) {
            data[out_ + 1][inrange[0] + plus + 1] = rgb;
            data[out_ + 1][inrange[1] + plus + 1] = rgb;
            data[out_ + 1][inrange[0] - plus + 1] = rgb;
            data[out_ + 1][inrange[1] - plus + 1] = rgb;
          }
        }

        for (int in_ = inrange[0]; in_ < inrange[1]; in_++) {
          for (int plus = 0; plus <= pl->meshlines_width; plus++) {
            data[outrange[0] + plus + 1][in_ + 1] = rgb;
            data[outrange[1] + plus + 1][in_ + 1] = rgb;
            data[outrange[0] - plus + 1][in_ + 1] = rgb;
            data[outrange[1] - plus + 1][in_ + 1] = rgb;
          }
        }

      } // end if(in mesh)
    }
  } // end outer loops

}

void
voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, hid_t* dset,
           hid_t* memspace)
{
  // Create dataspace/dataset for voxel data
  *dspace = H5Screate_simple(3, dims, nullptr);
  *dset = H5Dcreate(file_id, "data", H5T_NATIVE_INT, *dspace, H5P_DEFAULT,
                    H5P_DEFAULT, H5P_DEFAULT);

  // Create dataspace for a slice of the voxel
  hsize_t dims_slice[2] {dims[1], dims[2]};
  *memspace = H5Screate_simple(2, dims_slice, nullptr);

  // Select hyperslab in dataspace
  hsize_t start[3] {0, 0, 0};
  hsize_t count[3] {1, dims[1], dims[2]};
  H5Sselect_hyperslab(*dspace, H5S_SELECT_SET, start, nullptr, count, nullptr);
}

void
voxel_write_slice(int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf)
{
  hssize_t offset[3] {x - 1, 0, 0};
  H5Soffset_simple(dspace, offset);
  H5Dwrite(dset, H5T_NATIVE_INT, memspace, dspace, H5P_DEFAULT, buf);
}

void
voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace)
{
  H5Dclose(dset);
  H5Sclose(dspace);
  H5Sclose(memspace);
}

} // namespace openmc
<commit_msg>Correction to make sure results match current expected output.<commit_after>#include <fstream>

#include "openmc/plot.h"
#include "openmc/constants.h"
#include "openmc/settings.h"
#include "openmc/error.h"
#include "openmc/particle.h"
#include "openmc/geometry.h"
#include "openmc/cell.h"
#include "openmc/material.h"
#include "openmc/string_functions.h"
#include "openmc/mesh.h"

namespace openmc {

const int RED   = 1;
const int GREEN = 2;
const int BLUE  = 3;

const int WHITE[3] = {255, 255, 255};
const int NULLRGB[3] = {0, 0, 0};

//===============================================================================
// RUN_PLOT controls the logic for making one or many plots
//===============================================================================

int openmc_plot_geometry() {
  int err;

  for (auto i : n_plots) {
    ObjectPlot* pl = plots[i];

    std::stringstream ss;
    ss << "Processing plot " << pl->id << ": "
       << pl->path_plot << "...";
      write_message(ss.str(), 5);

      if (PLOT_TYPE::SLICE == pl->type) {
        // create 2D image
        // create_ppm(pl);
        continue;
      } else if (PLOT_TYPE::VOXEL == pl->type) {
        // create voxel file for 3D viewing
        // create_voxel(pl);
        continue;
      }

  }

  return 0;
}

//===============================================================================
// CREATE_PPM creates an image based on user input from a plots.xml <plot>
// specification in the portable pixmap format (PPM)
//===============================================================================

void create_ppm(ObjectPlot* pl) {

  int width = pl->pixels[0];
  int height = pl->pixels[1];

  double in_pixel = (pl->width[0])/double(width);
  double out_pixel = (pl->width[1])/double(height);

  std::vector< std::vector< std::vector<int> > > data;

  data.resize(width);
  for (auto & i : data) {
    i.resize(height);
    for (auto & j : i) {
      j.resize(3);
    }
  }

  int in_i, out_i;
  double xyz[3];
  if (PLOT_BASIS::XY == pl->basis) {
    in_i = 0;
    out_i = 1;
    xyz[0] = pl->origin[0] - pl->width[0] / TWO;
    xyz[1] = pl->origin[1] + pl->width[1] / TWO;
    xyz[2] = pl->origin[2];
  } else if (PLOT_BASIS::XZ == pl->basis) {
    in_i = 0;
    out_i = 2;
    xyz[0] = pl->origin[0] - pl->width[0] / TWO;
    xyz[1] = pl->origin[1];
    xyz[2] = pl->origin[2] + pl->width[1] / TWO;
  } else if (PLOT_BASIS::YZ == pl->basis) {
    in_i = 1;
    out_i = 2;
    xyz[0] = pl->origin[0];
    xyz[1] = pl->origin[1] - pl->width[0] / TWO;
    xyz[2] = pl->origin[2] + pl->width[1] / TWO;
  }

  double dir[3] = {HALF, HALF, HALF};
  Particle *p = new Particle();
  p->initialize();
  std::copy(xyz, xyz+3, p->coord[0].xyz);
  std::copy(dir, dir+3, p->coord[0].uvw);
  p->coord[0].universe = openmc_root_universe;

  // local variables
  int rgb[3];
  int id;
  for (int y = 0; y < height; y++) {
    p->coord[0].xyz[out_i] = xyz[out_i] - out_pixel*(y);
    for (int x = 0; x < width; x++) {
      p->coord[0].xyz[in_i] = xyz[in_i] + in_pixel*(x);
      position_rgb(p, pl, rgb, id);
      data[x][y][0] = rgb[0];
      data[x][y][1] = rgb[1];
      data[x][y][2] = rgb[2];
    }
  }

  if (pl->index_meshlines_mesh >= 0) { draw_mesh_lines(pl, data); }

  output_ppm(pl, data);

}

//===============================================================================
// POSITION_RGB computes the red/green/blue values for a given plot with the
// current particle's position
//===============================================================================

void position_rgb(Particle* p, ObjectPlot* pl, int rgb[3], int &id) {
  bool found_cell;

  p->n_coord = 1;

  found_cell = find_cell(p, 0);

  int j = p->n_coord - 1;

  if (settings::check_overlaps) { check_cell_overlap(p); }

  // Set coordinate level if specified
  if (pl->level >= 0) {j = pl->level + 1;}

  Cell* c;

  if (!found_cell) {
    // If no cell, revert to default color
    std::copy(pl->not_found.rgb,
              pl->not_found.rgb + 3,
              rgb);
    id = -1;
  } else {
    if (PLOT_COLOR_BY::MATS == pl->color_by) {
      // Assign color based on material
      c = cells[p->coord[j].cell];
      if (c->type_ == FILL_UNIVERSE) {
        // If we stopped on a middle universe level, treat as if not found
        std::copy(pl->not_found.rgb,
                  pl->not_found.rgb + 3,
                  rgb);
        id = -1;
      } else if (p->material == MATERIAL_VOID) {
        // By default, color void cells white
        std::copy(WHITE, WHITE+3, rgb);
        id = -1;
      } else {
        std::copy(pl->colors[p->material - 1].rgb,
                  pl->colors[p->material - 1].rgb + 3,
                  rgb);
        id = materials[p->material - 1]->id;
      }

    } else if (PLOT_COLOR_BY::CELLS == pl->color_by) {
      // Assign color based on cell
      std::copy(pl->colors[p->coord[j].cell].rgb,
                pl->colors[p->coord[j].cell].rgb + 3,
                rgb);
      id = cells[p->coord[j].cell]->id_;
    } else {
      std::copy(NULLRGB, NULLRGB+3, rgb);
      id = -1;
    }

  } // endif found_cell
}

//===============================================================================
// OUTPUT_PPM writes out a previously generated image to a PPM file
//===============================================================================

  void output_ppm(ObjectPlot* pl,
                  const std::vector< std::vector< std::vector<int> > > &data)
{

  // Open PPM file for writing
  std::string fname = std::string(pl->path_plot);
  fname = strtrim(fname);
  std::ofstream of;

  of.open(fname);

  // Write header
  of << "P6" << std::endl;
  of << pl->pixels[0] << " " << pl->pixels[1] << std::endl;
  of << "255" << std::endl;
  of.close();

  of.open(fname, std::ios::binary | std::ios::app);
  // Write color for each pixel
  for (int y = 0; y < pl->pixels[1]; y++) {
    for (int x = 0; x < pl->pixels[0]; x++) {
      std::vector<int> rgb = data[x][y];
      of.write((char*)&rgb[0], 1);
      of.write((char*)&rgb[1], 1);
      of.write((char*)&rgb[2], 1);
    }
  }
  // Close file
  // THIS IS HERE TO MATCH FORTRAN VERSION, NOT NECESSARY
  of << std::endl;
  of.close();
}

//===============================================================================
// DRAW_MESH_LINES draws mesh line boundaries on an image
//===============================================================================

void draw_mesh_lines(ObjectPlot *pl,
                     std::vector< std::vector< std::vector<int> > > &data) {

  std::vector<int> rgb; rgb.resize(3);
  rgb[0] = pl->meshlines_color.rgb[0];
  rgb[1] = pl->meshlines_color.rgb[1];
  rgb[2] = pl->meshlines_color.rgb[2];

  int outer, inner;
  switch(pl->basis){
  case PLOT_BASIS::XY :
    outer = 0;
    inner = 1;
    break;
  case PLOT_BASIS::XZ :
    outer = 0;
    inner = 2;
    break;
  case PLOT_BASIS::YZ :
    outer = 1;
    inner = 2;
    break;
  }

  double xyz_ll_plot[3], xyz_ur_plot[3];
  std::copy((double*)&pl->origin, (double*)&pl->origin + 3, xyz_ll_plot);
  std::copy((double*)&pl->origin, (double*)&pl->origin + 3, xyz_ur_plot);

  xyz_ll_plot[outer] = pl->origin[outer] - pl->width[0] / TWO;
  xyz_ll_plot[inner] = pl->origin[inner] - pl->width[1] / TWO;
  xyz_ur_plot[outer] = pl->origin[outer] + pl->width[0] / TWO;
  xyz_ur_plot[inner] = pl->origin[inner] + pl->width[1] / TWO;

  int width[3];
  width[0] = xyz_ur_plot[0] - xyz_ll_plot[0];
  width[1] = xyz_ur_plot[1] - xyz_ll_plot[1];
  width[2] = xyz_ur_plot[2] - xyz_ll_plot[2];

  auto &m = meshes[pl->index_meshlines_mesh];

  int ijk_ll[3], ijk_ur[3];
  bool in_mesh;
  m->get_indices(Position(xyz_ll_plot), &(ijk_ll[0]), &in_mesh);
  m->get_indices(Position(xyz_ur_plot), &(ijk_ur[0]), &in_mesh);

  double frac;
  int outrange[3], inrange[3];
  double xyz_ll[3], xyz_ur[3];
  // sweep through all meshbins on this plane and draw borders
  for (int i = ijk_ll[outer]; i <= ijk_ur[outer] + 1; i++) {
    for (int j = ijk_ll[inner]; j <= ijk_ur[inner] + 1; j++) {
      // check if we're in the mesh for this ijk
      if (i > 0 && i <= m->shape_[outer] && j >0 && j <= m->shape_[inner] ) {

        // get xyz's of lower left and upper right of this mesh cell
        xyz_ll[outer] = m->lower_left_[outer] + m->width_[outer] * (i - 1);
        xyz_ll[inner] = m->lower_left_[inner] + m->width_[inner] * (j - 1);
        xyz_ur[outer] = m->lower_left_[outer] + m->width_[outer] * i;
        xyz_ur[inner] = m->lower_left_[inner] + m->width_[inner] * j;

        // map the xyz ranges to pixel ranges
        frac = (xyz_ll[outer] - xyz_ll_plot[outer]) / width[outer];
        outrange[0] = int(frac * double(pl->pixels[0]));
        frac = (xyz_ur[outer] - xyz_ll_plot[outer]) / width[outer];
        outrange[1] = int(frac * double(pl->pixels[0]));

        frac = (xyz_ur[inner] - xyz_ll_plot[inner]) / width[inner];
        inrange[0] = int((ONE - frac) * (double)pl->pixels[1]);
        frac = (xyz_ll[inner] - xyz_ll_plot[inner]) / width[inner];
        inrange[1] = int((ONE - frac) * (double)pl->pixels[1]);

        // draw lines
        for (int out_ = outrange[0]; out_ <= outrange[1]; out_++) {
          for (int plus = 0; plus <= pl->meshlines_width; plus++) {
            data[out_][inrange[0] + plus] = rgb;
            data[out_][inrange[1] + plus] = rgb;
            data[out_][inrange[0] - plus] = rgb;
            data[out_][inrange[1] - plus] = rgb;
          }
        }

        for (int in_ = inrange[0]; in_ <= inrange[1]; in_++) {
          for (int plus = 0; plus <= pl->meshlines_width; plus++) {
            data[outrange[0] + plus][in_] = rgb;
            data[outrange[1] + plus][in_] = rgb;
            data[outrange[0] - plus][in_] = rgb;
            data[outrange[1] - plus][in_] = rgb;
          }
        }

      } // end if(in mesh)
    }
  } // end outer loops

}

void
voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, hid_t* dset,
           hid_t* memspace)
{
  // Create dataspace/dataset for voxel data
  *dspace = H5Screate_simple(3, dims, nullptr);
  *dset = H5Dcreate(file_id, "data", H5T_NATIVE_INT, *dspace, H5P_DEFAULT,
                    H5P_DEFAULT, H5P_DEFAULT);

  // Create dataspace for a slice of the voxel
  hsize_t dims_slice[2] {dims[1], dims[2]};
  *memspace = H5Screate_simple(2, dims_slice, nullptr);

  // Select hyperslab in dataspace
  hsize_t start[3] {0, 0, 0};
  hsize_t count[3] {1, dims[1], dims[2]};
  H5Sselect_hyperslab(*dspace, H5S_SELECT_SET, start, nullptr, count, nullptr);
}

void
voxel_write_slice(int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf)
{
  hssize_t offset[3] {x - 1, 0, 0};
  H5Soffset_simple(dspace, offset);
  H5Dwrite(dset, H5T_NATIVE_INT, memspace, dspace, H5P_DEFAULT, buf);
}

void
voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace)
{
  H5Dclose(dset);
  H5Sclose(dspace);
  H5Sclose(memspace);
}

} // namespace openmc
<|endoftext|>


<commit_before>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skin.h"
#include "utils/polygonUtils.h"

#define MIN_AREA_SIZE (0.4 * 0.4)

namespace cura
{

void generateSkins(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int wall_line_count, int innermost_wall_extrusion_width, int insetCount, bool no_small_gaps_heuristic, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    generateSkinAreas(layerNr, storage, innermost_wall_extrusion_width, downSkinCount, upSkinCount, wall_line_count, no_small_gaps_heuristic);

    SliceLayer* layer = &storage.layers[layerNr];
    for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
    {
        SliceLayerPart* part = &layer->parts[partNr];
        generateSkinInsets(part, extrusionWidth, insetCount, avoidOverlappingPerimeters_0, avoidOverlappingPerimeters);
    }
}

void generateSkinAreas(int layer_nr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int downSkinCount, int upSkinCount, int wall_line_count, bool no_small_gaps_heuristic)
{
    SliceLayer& layer = storage.layers[layer_nr];

    if (downSkinCount == 0 && upSkinCount == 0)
    {
        return;
    }

    for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
    {
        SliceLayerPart& part = layer.parts[partNr];

        if (int(part.insets.size()) < wall_line_count)
        {
            continue; // the last wall is not present, the part should only get inter preimeter gaps, but no skin.
        }

        Polygons upskin = part.insets.back().offset(-innermost_wall_extrusion_width/2);
        Polygons downskin = (downSkinCount == 0)? Polygons() : upskin;
        if (upSkinCount == 0) upskin = Polygons();

        auto getInsidePolygons = [&part](SliceLayer& layer2)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2.parts)
                {
                    if (part.boundaryBox.hit(part2.boundaryBox))
                        result.add(part2.insets.back());
                }
                return result;
            };

        if (no_small_gaps_heuristic)
        {
            if (static_cast<int>(layer_nr - downSkinCount) >= 0)
            {
                downskin = downskin.difference(getInsidePolygons(storage.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
            }

            if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(storage.layers.size()))
            {
                upskin = upskin.difference(getInsidePolygons(storage.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
            }
        }
        else
        {
            if (layer_nr >= downSkinCount && downSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr - 1]);
                for (int downskin_layer_nr = layer_nr - downSkinCount; downskin_layer_nr < layer_nr - 1; downskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[downskin_layer_nr]));
                }
                downskin = downskin.difference(not_air); // skin overlaps with the walls
            }

            if (layer_nr < static_cast<int>(storage.layers.size()) - downSkinCount && upSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr + 1]);
                for (int upskin_layer_nr = layer_nr + 2; upskin_layer_nr < layer_nr + upSkinCount + 1; upskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[upskin_layer_nr]));
                }
                upskin = upskin.difference(not_air); // skin overlaps with the walls
            }
        }

        Polygons skin = upskin.unionPolygons(downskin);

        skin.removeSmallAreas(MIN_AREA_SIZE);

        for (PolygonsPart& skin_area_part : skin.splitIntoParts())
        {
            part.skin_parts.emplace_back();
            part.skin_parts.back().outline = skin_area_part;
        }
    }
}

void generateSkinInsets(SliceLayerPart* part, int extrusionWidth, int insetCount, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    if (insetCount == 0)
    {
        return;
    }

    for (SkinPart& skin_part : part->skin_parts)
    {
        for(int i=0; i<insetCount; i++)
        {
            skin_part.insets.push_back(Polygons());
            if (i == 0)
            {
                PolygonUtils::offsetSafe(skin_part.outline, - extrusionWidth/2, extrusionWidth, skin_part.insets[0], avoidOverlappingPerimeters_0);
                Polygons in_between = skin_part.outline.difference(skin_part.insets[0].offset(extrusionWidth/2));
                skin_part.perimeterGaps.add(in_between);
            } else
            {
                PolygonUtils::offsetExtrusionWidth(skin_part.insets[i-1], true, extrusionWidth, skin_part.insets[i], &skin_part.perimeterGaps, avoidOverlappingPerimeters);
            }

            // optimize polygons: remove unnnecesary verts
            skin_part.insets[i].simplify();
            if (skin_part.insets[i].size() < 1)
            {
                skin_part.insets.pop_back();
                break;
            }
        }
    }
}

void generateInfill(int layerNr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int infill_skin_overlap, int wall_line_count)
{
    SliceLayer& layer = storage.layers[layerNr];

    for(SliceLayerPart& part : layer.parts)
    {
        if (int(part.insets.size()) < wall_line_count)
        {
            part.infill_area.emplace_back(); // put empty polygon as (uncombined) infill
            continue; // the last wall is not present, the part should only get inter preimeter gaps, but no infill.
        }
        Polygons infill = part.insets.back().offset(-innermost_wall_extrusion_width / 2 - infill_skin_overlap);

        for(SliceLayerPart& part2 : layer.parts)
        {
            if (part.boundaryBox.hit(part2.boundaryBox))
            {
                for(SkinPart& skin_part : part2.skin_parts)
                {
                    infill = infill.difference(skin_part.outline);
                }
            }
        }
        infill.removeSmallAreas(MIN_AREA_SIZE);

        part.infill_area.push_back(infill.offset(infill_skin_overlap));
    }
}

void combineInfillLayers(SliceMeshStorage& storage,unsigned int amount)
{
    if(amount <= 1) //If we must combine 1 layer, nothing needs to be combined. Combining 0 layers is invalid.
    {
        return;
    }
    if(storage.layers.empty() || storage.layers.size() - 1 < static_cast<size_t>(storage.getSettingAsCount("top_layers")) || storage.getSettingAsCount("infill_line_distance") <= 0) //No infill is even generated.
    {
        return;
    }
    /* We need to round down the layer index we start at to the nearest
    divisible index. Otherwise we get some parts that have infill at divisible
    layers and some at non-divisible layers. Those layers would then miss each
    other. */
    size_t min_layer = storage.getSettingAsCount("bottom_layers") + amount - 1;
    min_layer -= min_layer % amount; //Round upwards to the nearest layer divisible by infill_sparse_combine.
    size_t max_layer = storage.layers.size() - 1 - storage.getSettingAsCount("top_layers");
    max_layer -= max_layer % amount; //Round downwards to the nearest layer divisible by infill_sparse_combine.
    for(size_t layer_idx = min_layer;layer_idx <= max_layer;layer_idx += amount) //Skip every few layers, but extrude more.
    {
        SliceLayer* layer = &storage.layers[layer_idx];

        for(unsigned int n = 1;n < amount;n++)
        {
            if(layer_idx < n)
            {
                break;
            }

            SliceLayer* layer2 = &storage.layers[layer_idx - n];
            for(SliceLayerPart& part : layer->parts)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2->parts)
                {
                    if(part.boundaryBox.hit(part2.boundaryBox))
                    {
                        Polygons intersection = part.infill_area[n - 1].intersection(part2.infill_area[0]).offset(-200).offset(200);
                        result.add(intersection);
                        part.infill_area[n - 1] = part.infill_area[n - 1].difference(intersection);
                        part2.infill_area[0] = part2.infill_area[0].difference(intersection);
                    }
                }

                part.infill_area.push_back(result);
            }
        }
    }
}

void generatePerimeterGaps(int layer_nr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount)
{
    SliceLayer& layer = storage.layers[layer_nr];

    for (SliceLayerPart& part : layer.parts)
    { // handle gaps between perimeters etc.
        if (downSkinCount > 0 && upSkinCount > 0 && // note: if both are zero or less, then all gaps will be used
            layer_nr >= downSkinCount && layer_nr < static_cast<int>(storage.layers.size() - upSkinCount)) // remove gaps which appear within print, i.e. not on the bottom most or top most skin
        {
            Polygons outlines_above;
            for (SliceLayerPart& part_above : storage.layers[layer_nr + upSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_above.boundaryBox))
                {
                    outlines_above.add(part_above.outline);
                }
            }
            Polygons outlines_below;
            for (SliceLayerPart& part_below : storage.layers[layer_nr - downSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_below.boundaryBox))
                {
                    outlines_below.add(part_below.outline);
                }
            }
            part.perimeterGaps = part.perimeterGaps.intersection(outlines_above.xorPolygons(outlines_below));
        }
        part.perimeterGaps.removeSmallAreas(MIN_AREA_SIZE);
    }
}

}//namespace cura
<commit_msg>bugfix: alternate extra wall had skin overlapping with inner wall (CURA-1233)<commit_after>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skin.h"
#include "utils/polygonUtils.h"

#define MIN_AREA_SIZE (0.4 * 0.4)

namespace cura
{

void generateSkins(int layerNr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int wall_line_count, int innermost_wall_extrusion_width, int insetCount, bool no_small_gaps_heuristic, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    generateSkinAreas(layerNr, storage, innermost_wall_extrusion_width, downSkinCount, upSkinCount, wall_line_count, no_small_gaps_heuristic);

    SliceLayer* layer = &storage.layers[layerNr];
    for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
    {
        SliceLayerPart* part = &layer->parts[partNr];
        generateSkinInsets(part, extrusionWidth, insetCount, avoidOverlappingPerimeters_0, avoidOverlappingPerimeters);
    }
}

void generateSkinAreas(int layer_nr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int downSkinCount, int upSkinCount, int wall_line_count, bool no_small_gaps_heuristic)
{
    SliceLayer& layer = storage.layers[layer_nr];

    if (downSkinCount == 0 && upSkinCount == 0)
    {
        return;
    }

    for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
    {
        SliceLayerPart& part = layer.parts[partNr];

        if (int(part.insets.size()) < wall_line_count)
        {
            continue; // the last wall is not present, the part should only get inter preimeter gaps, but no skin.
        }

        Polygons upskin = part.insets.back().offset(-innermost_wall_extrusion_width/2);
        Polygons downskin = (downSkinCount == 0)? Polygons() : upskin;
        if (upSkinCount == 0) upskin = Polygons();

        auto getInsidePolygons = [&part, wall_line_count](SliceLayer& layer2)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2.parts)
                {
                    if (part.boundaryBox.hit(part2.boundaryBox))
                        result.add(part2.insets[wall_line_count - 1]);
                }
                return result;
            };

        if (no_small_gaps_heuristic)
        {
            if (static_cast<int>(layer_nr - downSkinCount) >= 0)
            {
                downskin = downskin.difference(getInsidePolygons(storage.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
            }

            if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(storage.layers.size()))
            {
                upskin = upskin.difference(getInsidePolygons(storage.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
            }
        }
        else
        {
            if (layer_nr >= downSkinCount && downSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr - 1]);
                for (int downskin_layer_nr = layer_nr - downSkinCount; downskin_layer_nr < layer_nr - 1; downskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[downskin_layer_nr]));
                }
                downskin = downskin.difference(not_air); // skin overlaps with the walls
            }

            if (layer_nr < static_cast<int>(storage.layers.size()) - downSkinCount && upSkinCount > 0)
            {
                Polygons not_air = getInsidePolygons(storage.layers[layer_nr + 1]);
                for (int upskin_layer_nr = layer_nr + 2; upskin_layer_nr < layer_nr + upSkinCount + 1; upskin_layer_nr++)
                {
                    not_air = not_air.intersection(getInsidePolygons(storage.layers[upskin_layer_nr]));
                }
                upskin = upskin.difference(not_air); // skin overlaps with the walls
            }
        }

        Polygons skin = upskin.unionPolygons(downskin);

        skin.removeSmallAreas(MIN_AREA_SIZE);

        for (PolygonsPart& skin_area_part : skin.splitIntoParts())
        {
            part.skin_parts.emplace_back();
            part.skin_parts.back().outline = skin_area_part;
        }
    }
}

void generateSkinInsets(SliceLayerPart* part, int extrusionWidth, int insetCount, bool avoidOverlappingPerimeters_0, bool avoidOverlappingPerimeters)
{
    if (insetCount == 0)
    {
        return;
    }

    for (SkinPart& skin_part : part->skin_parts)
    {
        for(int i=0; i<insetCount; i++)
        {
            skin_part.insets.push_back(Polygons());
            if (i == 0)
            {
                PolygonUtils::offsetSafe(skin_part.outline, - extrusionWidth/2, extrusionWidth, skin_part.insets[0], avoidOverlappingPerimeters_0);
                Polygons in_between = skin_part.outline.difference(skin_part.insets[0].offset(extrusionWidth/2));
                skin_part.perimeterGaps.add(in_between);
            } else
            {
                PolygonUtils::offsetExtrusionWidth(skin_part.insets[i-1], true, extrusionWidth, skin_part.insets[i], &skin_part.perimeterGaps, avoidOverlappingPerimeters);
            }

            // optimize polygons: remove unnnecesary verts
            skin_part.insets[i].simplify();
            if (skin_part.insets[i].size() < 1)
            {
                skin_part.insets.pop_back();
                break;
            }
        }
    }
}

void generateInfill(int layerNr, SliceMeshStorage& storage, int innermost_wall_extrusion_width, int infill_skin_overlap, int wall_line_count)
{
    SliceLayer& layer = storage.layers[layerNr];

    for(SliceLayerPart& part : layer.parts)
    {
        if (int(part.insets.size()) < wall_line_count)
        {
            part.infill_area.emplace_back(); // put empty polygon as (uncombined) infill
            continue; // the last wall is not present, the part should only get inter preimeter gaps, but no infill.
        }
        Polygons infill = part.insets.back().offset(-innermost_wall_extrusion_width / 2 - infill_skin_overlap);

        for(SliceLayerPart& part2 : layer.parts)
        {
            if (part.boundaryBox.hit(part2.boundaryBox))
            {
                for(SkinPart& skin_part : part2.skin_parts)
                {
                    infill = infill.difference(skin_part.outline);
                }
            }
        }
        infill.removeSmallAreas(MIN_AREA_SIZE);

        part.infill_area.push_back(infill.offset(infill_skin_overlap));
    }
}

void combineInfillLayers(SliceMeshStorage& storage,unsigned int amount)
{
    if(amount <= 1) //If we must combine 1 layer, nothing needs to be combined. Combining 0 layers is invalid.
    {
        return;
    }
    if(storage.layers.empty() || storage.layers.size() - 1 < static_cast<size_t>(storage.getSettingAsCount("top_layers")) || storage.getSettingAsCount("infill_line_distance") <= 0) //No infill is even generated.
    {
        return;
    }
    /* We need to round down the layer index we start at to the nearest
    divisible index. Otherwise we get some parts that have infill at divisible
    layers and some at non-divisible layers. Those layers would then miss each
    other. */
    size_t min_layer = storage.getSettingAsCount("bottom_layers") + amount - 1;
    min_layer -= min_layer % amount; //Round upwards to the nearest layer divisible by infill_sparse_combine.
    size_t max_layer = storage.layers.size() - 1 - storage.getSettingAsCount("top_layers");
    max_layer -= max_layer % amount; //Round downwards to the nearest layer divisible by infill_sparse_combine.
    for(size_t layer_idx = min_layer;layer_idx <= max_layer;layer_idx += amount) //Skip every few layers, but extrude more.
    {
        SliceLayer* layer = &storage.layers[layer_idx];

        for(unsigned int n = 1;n < amount;n++)
        {
            if(layer_idx < n)
            {
                break;
            }

            SliceLayer* layer2 = &storage.layers[layer_idx - n];
            for(SliceLayerPart& part : layer->parts)
            {
                Polygons result;
                for(SliceLayerPart& part2 : layer2->parts)
                {
                    if(part.boundaryBox.hit(part2.boundaryBox))
                    {
                        Polygons intersection = part.infill_area[n - 1].intersection(part2.infill_area[0]).offset(-200).offset(200);
                        result.add(intersection);
                        part.infill_area[n - 1] = part.infill_area[n - 1].difference(intersection);
                        part2.infill_area[0] = part2.infill_area[0].difference(intersection);
                    }
                }

                part.infill_area.push_back(result);
            }
        }
    }
}

void generatePerimeterGaps(int layer_nr, SliceMeshStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount)
{
    SliceLayer& layer = storage.layers[layer_nr];

    for (SliceLayerPart& part : layer.parts)
    { // handle gaps between perimeters etc.
        if (downSkinCount > 0 && upSkinCount > 0 && // note: if both are zero or less, then all gaps will be used
            layer_nr >= downSkinCount && layer_nr < static_cast<int>(storage.layers.size() - upSkinCount)) // remove gaps which appear within print, i.e. not on the bottom most or top most skin
        {
            Polygons outlines_above;
            for (SliceLayerPart& part_above : storage.layers[layer_nr + upSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_above.boundaryBox))
                {
                    outlines_above.add(part_above.outline);
                }
            }
            Polygons outlines_below;
            for (SliceLayerPart& part_below : storage.layers[layer_nr - downSkinCount].parts)
            {
                if (part.boundaryBox.hit(part_below.boundaryBox))
                {
                    outlines_below.add(part_below.outline);
                }
            }
            part.perimeterGaps = part.perimeterGaps.intersection(outlines_above.xorPolygons(outlines_below));
        }
        part.perimeterGaps.removeSmallAreas(MIN_AREA_SIZE);
    }
}

}//namespace cura
<|endoftext|>


<commit_before>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * span.cpp
 * - Spans and error handling
 */
#include <functional>
#include <iostream>
#include <span.hpp>
#include <parse/lex.hpp>
#include <common.hpp>

Span::Span(const Span& x):
    outer_span(x.outer_span),
    filename(x.filename),
    start_line(x.start_line),
    start_ofs(x.start_ofs),
    end_line(x.end_line),
    end_ofs(x.end_ofs)
{
}
Span::Span(const Position& pos):
    outer_span(),
    filename(pos.filename),
    start_line(pos.line),
    start_ofs(pos.ofs),
    end_line(pos.line),
    end_ofs(pos.ofs)
{
}
Span::Span():
    outer_span(),
    filename("")/*,
    start_line(0), start_ofs(0),
    end_line(0), end_ofs(0) // */
{
    //DEBUG("Empty span");
    //filename = FMT(":" << __builtin_return_address(0));
}

namespace {
    void print_span_message(const Span& sp, ::std::function<void(::std::ostream&)> tag, ::std::function<void(::std::ostream&)> msg)
    {
        auto& sink = ::std::cerr;
        sink << sp.filename << ":" << sp.start_line << ": ";
        tag(sink);
        sink << ":";
        msg(sink);
        sink << ::std::endl;
        const auto* parent = sp.outer_span.get();
        while(parent)
        {
            sink << parent->filename << ":" << parent->start_line << ": note: From here" << ::std::endl;
            parent = parent->outer_span.get();
        }
    }
}
void Span::bug(::std::function<void(::std::ostream&)> msg) const
{
    print_span_message(*this, [](auto& os){os << "BUG";}, msg);
#ifndef _WIN32
    abort();
#else
    exit(1);
#endif
}

void Span::error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [&](auto& os){os << "error:" << tag;}, msg);
#ifndef _WIN32
    abort();
#else
    exit(1);
#endif
}
void Span::warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [&](auto& os){os << "warning" << tag;}, msg);
}
void Span::note(::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [](auto& os){os << "note";}, msg);
}

::std::ostream& operator<<(::std::ostream& os, const Span& sp)
{
    os << sp.filename << ":" << sp.start_line;
    return os;
}
<commit_msg>Span - Fix lack of separator in warnings<commit_after>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * span.cpp
 * - Spans and error handling
 */
#include <functional>
#include <iostream>
#include <span.hpp>
#include <parse/lex.hpp>
#include <common.hpp>

Span::Span(const Span& x):
    outer_span(x.outer_span),
    filename(x.filename),
    start_line(x.start_line),
    start_ofs(x.start_ofs),
    end_line(x.end_line),
    end_ofs(x.end_ofs)
{
}
Span::Span(const Position& pos):
    outer_span(),
    filename(pos.filename),
    start_line(pos.line),
    start_ofs(pos.ofs),
    end_line(pos.line),
    end_ofs(pos.ofs)
{
}
Span::Span():
    outer_span(),
    filename("")/*,
    start_line(0), start_ofs(0),
    end_line(0), end_ofs(0) // */
{
    //DEBUG("Empty span");
    //filename = FMT(":" << __builtin_return_address(0));
}

namespace {
    void print_span_message(const Span& sp, ::std::function<void(::std::ostream&)> tag, ::std::function<void(::std::ostream&)> msg)
    {
        auto& sink = ::std::cerr;
        sink << sp.filename << ":" << sp.start_line << ": ";
        tag(sink);
        sink << ":";
        msg(sink);
        sink << ::std::endl;
        const auto* parent = sp.outer_span.get();
        while(parent)
        {
            sink << parent->filename << ":" << parent->start_line << ": note: From here" << ::std::endl;
            parent = parent->outer_span.get();
        }
    }
}
void Span::bug(::std::function<void(::std::ostream&)> msg) const
{
    print_span_message(*this, [](auto& os){os << "BUG";}, msg);
#ifndef _WIN32
    abort();
#else
    exit(1);
#endif
}

void Span::error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [&](auto& os){os << "error:" << tag;}, msg);
#ifndef _WIN32
    abort();
#else
    exit(1);
#endif
}
void Span::warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [&](auto& os){os << "warn:" << tag;}, msg);
}
void Span::note(::std::function<void(::std::ostream&)> msg) const {
    print_span_message(*this, [](auto& os){os << "note:";}, msg);
}

::std::ostream& operator<<(::std::ostream& os, const Span& sp)
{
    os << sp.filename << ":" << sp.start_line;
    return os;
}
<|endoftext|>


<commit_before>#include <sched.h>
#include <sys/types.h>

#include "utils.hh"

int coin_get_current_cpu(void)
{
	return sched_getcpu();
}

void coin_set_cpu(pid_t pid, int cpu)
{
	// Switching CPU while running will cause icache
	// conflicts. So let's just forbid that.

	cpu_set_t *set = CPU_ALLOC(1);
	panic_if (!set,
			"Can't allocate CPU set!\n");
	CPU_SET(cpu, set);
	panic_if (sched_setaffinity(pid, CPU_ALLOC_SIZE(1), set) < 0,
			"Can't set CPU affinity. Coincident won't work");
	CPU_FREE(set);
}
<commit_msg>utils: Zero the CPU set before adding to it<commit_after>#include <sched.h>
#include <sys/types.h>

#include "utils.hh"

int coin_get_current_cpu(void)
{
	return sched_getcpu();
}

void coin_set_cpu(pid_t pid, int cpu)
{
	// Switching CPU while running will cause icache
	// conflicts. So let's just forbid that.

	cpu_set_t *set = CPU_ALLOC(1);
	panic_if (!set,
			"Can't allocate CPU set!\n");
	CPU_ZERO_S(CPU_ALLOC_SIZE(1), set);
	CPU_SET(cpu, set);
	panic_if (sched_setaffinity(pid, CPU_ALLOC_SIZE(1), set) < 0,
			"Can't set CPU affinity. Coincident won't work");
	CPU_FREE(set);
}
<|endoftext|>


<commit_before>#include "HorizontalSlider.h"

HorizontalSlider::HorizontalSlider(
    std::wstring bitmapName, int x, int y, int width, int height) :
SliderKnob(bitmapName, x, y, width, height) {
    _units = _track.Width - _rect.Width;
}

}

float HorizontalSlider::Value() const {
    int xPos = X() - TrackX();
    int xMax = TrackWidth() - _rect.Width;
    return (float) xPos / (float) xMax;
}

void HorizontalSlider::Value(float value) {
    Meter::Value(value);
    X(TrackX() + CalcUnits());
}

bool HorizontalSlider::Vertical() const {
    return false;
}
<commit_msg>Implement Draw()<commit_after>#include "HorizontalSlider.h"

HorizontalSlider::HorizontalSlider(
    std::wstring bitmapName, int x, int y, int width, int height) :
SliderKnob(bitmapName, x, y, width, height) {
    _units = _track.Width - _rect.Width;
}

void HorizontalSlider::Draw(
        Gdiplus::Bitmap *buffer, Gdiplus::Graphics *graphics) {
    graphics->DrawImage(_bitmap, _rect,
        0, 0, _rect.Width, _rect.Height, Gdiplus::UnitPixel);
}

float HorizontalSlider::Value() const {
    int xPos = X() - TrackX();
    int xMax = TrackWidth() - _rect.Width;
    return (float) xPos / (float) xMax;
}

void HorizontalSlider::Value(float value) {
    Meter::Value(value);
    X(TrackX() + CalcUnits());
}

bool HorizontalSlider::Vertical() const {
    return false;
}
<|endoftext|>


<commit_before>/**
 * v8cgi - (fast)cgi binary
 */

#include <v8.h>
#include <v8-debug.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "path.h"

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#  include <signal.h>
#endif

/**
 * Format for command line arguments
 *
 * as you can see if you wish to pass any arguments to v8, you MUST
 * put a -- surrounded by whitespace after all the v8 arguments
 *
 * any arguments after the v8_args but before the program_file are
 * used by v8cgi.
 */
static const char * v8cgi_usage = "v8cgi [v8_args --] [-v] [-h] [-c path] [-d port] program_file [argument ...]";

class v8cgi_CGI : public v8cgi_App {
public:
	/**
	 * Initialize from command line
	 */
	int init(int argc, char ** argv) {
		v8cgi_App::init();

		this->argv0 = (argc > 0 ? path_normalize(argv[0]) : std::string(""));

		if (argc == 1) {
			/* no command-line arguments, try looking for CGI env vars */
			this->fromEnvVars();
		}

		try {
			this->process_args(argc, argv);
		} catch (std::string e) {
			this->error(e.c_str(), __FILE__, __LINE__);
			return 1;
		}

		return 0;
	}

	/**
	 * STDIN reader
	 */
	size_t reader(char * destination, size_t amount) {
		return fread((void *) destination, sizeof(char), amount, stdin);
	}

	/**
	 * STDOUT writer
	 */
	size_t writer(const char * data, size_t amount) {
		return fwrite((void *) data, sizeof(char), amount, stdout);
	}

	/**
	 * STDERR error
	 */
	void error(const char * data, const char * file, int line) {
		fwrite((void *) data, sizeof(char), strlen(data), stderr);
		fwrite((void *) "\n", sizeof(char), 1, stderr);
	}

	/**
	 * STDOUT flush
	 * @return whether successful
	 */
	bool flush() {
		return (fflush(stdout) == 0);
	}

	void fromEnvVars() {
		char * env = getenv("PATH_TRANSLATED");
		if (!env) { env = getenv("SCRIPT_FILENAME"); }
		if (env) { this->mainfile = std::string(env); }
	}

private:
	std::string argv0;

	const char * instanceType() {
		return "cli";
	}

	const char * executableName() {
		return this->argv0.c_str();
	}

	/**
	 * Process command line arguments.
	 */
	void process_args(int argc, char ** argv) {
		std::string err = "Invalid command line usage.\n";
		err += "Correct usage: ";
		err += v8cgi_usage; /* see the v8cgi_usage definition for the format */

		int index = 0;

		/* see if we have v8 options */
		bool have_v8args = false;
		for (; index < argc; ++index) {
			/* FIXME: if there is a standalone "--" after the name of the script
			 then this breaks.  I can't figure out a solution to this, so
			 for now we don't support any standalone "--" after the script name.
			 One solution (and the way it currently works) is to require "--"
			 before all other args even if no v8 args are used, but that seems
			 I don't like this, but it is where we are right now. */
			if (std::string(argv[index]) == "--") {
				/* treat all previous arguments as v8 arguments */
				int v8argc = index;
				v8::V8::SetFlagsFromCommandLine(&v8argc, argv, true);
				index++; /* skip over the "--" */
				have_v8args = true;
				break;
			}
		}

		/* if there were no v8 args, then reset index to the first argument */
		if (!have_v8args) { index = 1; }

		/* scan for v8cgi-specific arguments now */
		while (index < argc) {
			std::string optname(argv[index]);
			if (optname[0] != '-') { break; } /* not starting with "-" => mainfile */
			if (optname.length() != 2) { throw err; } /* one-character options only */
			index++; /* skip the option name */

			switch (optname[1]) {
				case 'c':
					if (index >= argc) { throw err; } /* missing option value */
					this->cfgfile = argv[index];
#ifdef VERBOSE
					printf("cfgfile: %s\n", argv[index]);
#endif
					index++; /* skip the option value */
				break;

				case 'd':
					if (index >= argc) { throw err; } /* missing option value */
					v8::Debug::EnableAgent("v8cgi", atoi(argv[index]));
#ifdef VERBOSE
					printf("port: %s\n", argv[index]);
#endif
					index++; /* skip the option value */
				break;

				case 'h':
					printf(v8cgi_usage);
					printf("\n");
				break;

				case 'v':
					printf("v8cgi version %s", STRING(VERSION));
					printf("\n");
				break;

				default:
					throw err;
				break;
			}

		}

		if (index < argc) {
			/* argv[index] is the program file */
			this->mainfile = argv[index];
			/* expand mainfile to absolute path */
			if (!path_isabsolute(this->mainfile)) {
				std::string tmp = path_getcwd();
				tmp += "/";
				tmp += this->mainfile;
				this->mainfile = path_normalize(this->mainfile);
			}
			index++; /* skip over the program_file */
		}

		/* all the rest of the arguments are arguments to the program_file */
		for (; index < argc; ++index) {
#ifdef VERBOSE
			printf("program_arg: %s\n", argv[index]);
#endif
			this->mainfile_args.push_back(std::string(argv[index]));
		}
	}
};

#ifdef FASTCGI
	/**
	 * This is true only after we receive a signal to terminate
	 */
	bool exit_requested = false;

	void handle_sigterm(int param) {
		exit_requested = true;
 	}

	void handle_sigusr1(int param) {
		exit_requested = true;
	}
#endif

extern char ** environ;

int main(int argc, char ** argv) {
	int result = 0;
	v8cgi_CGI cgi;
	result = cgi.init(argc, argv);
	if (result) { exit(result); }

#ifdef FASTCGI
	signal(SIGTERM, handle_sigterm);
	signal(SIGUSR1, handle_sigusr1);
	/**
	 * FastCGI main loop
	 */
	while (FCGI_Accept() >= 0  && !exit_requested) {
		cgi.fromEnvVars();
#endif

		result = cgi.execute(environ);

#ifdef FASTCGI
		if (exit_requested) {
			FCGI_SetExitStatus(0);
			exit(0);
		} else {
			FCGI_SetExitStatus(result);
		}
	}
#endif

	return result;
}
<commit_msg>issue 69 - sigterm in fastcgi<commit_after>/**
 * v8cgi - (fast)cgi binary
 */

#include <v8.h>
#include <v8-debug.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include "path.h"

#ifdef FASTCGI
#  include <fcgi_stdio.h>
#  include <signal.h>
#endif

/**
 * Format for command line arguments
 *
 * as you can see if you wish to pass any arguments to v8, you MUST
 * put a -- surrounded by whitespace after all the v8 arguments
 *
 * any arguments after the v8_args but before the program_file are
 * used by v8cgi.
 */
static const char * v8cgi_usage = "v8cgi [v8_args --] [-v] [-h] [-c path] [-d port] program_file [argument ...]";

class v8cgi_CGI : public v8cgi_App {
public:
	/**
	 * Initialize from command line
	 */
	int init(int argc, char ** argv) {
		v8cgi_App::init();

		this->argv0 = (argc > 0 ? path_normalize(argv[0]) : std::string(""));

		if (argc == 1) {
			/* no command-line arguments, try looking for CGI env vars */
			this->fromEnvVars();
		}

		try {
			this->process_args(argc, argv);
		} catch (std::string e) {
			this->error(e.c_str(), __FILE__, __LINE__);
			return 1;
		}

		return 0;
	}

	/**
	 * STDIN reader
	 */
	size_t reader(char * destination, size_t amount) {
		return fread((void *) destination, sizeof(char), amount, stdin);
	}

	/**
	 * STDOUT writer
	 */
	size_t writer(const char * data, size_t amount) {
		return fwrite((void *) data, sizeof(char), amount, stdout);
	}

	/**
	 * STDERR error
	 */
	void error(const char * data, const char * file, int line) {
		fwrite((void *) data, sizeof(char), strlen(data), stderr);
		fwrite((void *) "\n", sizeof(char), 1, stderr);
	}

	/**
	 * STDOUT flush
	 * @return whether successful
	 */
	bool flush() {
		return (fflush(stdout) == 0);
	}

	void fromEnvVars() {
		char * env = getenv("PATH_TRANSLATED");
		if (!env) { env = getenv("SCRIPT_FILENAME"); }
		if (env) { this->mainfile = std::string(env); }
	}

private:
	std::string argv0;

	const char * instanceType() {
		return "cli";
	}

	const char * executableName() {
		return this->argv0.c_str();
	}

	/**
	 * Process command line arguments.
	 */
	void process_args(int argc, char ** argv) {
		std::string err = "Invalid command line usage.\n";
		err += "Correct usage: ";
		err += v8cgi_usage; /* see the v8cgi_usage definition for the format */

		int index = 0;

		/* see if we have v8 options */
		bool have_v8args = false;
		for (; index < argc; ++index) {
			/* FIXME: if there is a standalone "--" after the name of the script
			 then this breaks.  I can't figure out a solution to this, so
			 for now we don't support any standalone "--" after the script name.
			 One solution (and the way it currently works) is to require "--"
			 before all other args even if no v8 args are used, but that seems
			 I don't like this, but it is where we are right now. */
			if (std::string(argv[index]) == "--") {
				/* treat all previous arguments as v8 arguments */
				int v8argc = index;
				v8::V8::SetFlagsFromCommandLine(&v8argc, argv, true);
				index++; /* skip over the "--" */
				have_v8args = true;
				break;
			}
		}

		/* if there were no v8 args, then reset index to the first argument */
		if (!have_v8args) { index = 1; }

		/* scan for v8cgi-specific arguments now */
		while (index < argc) {
			std::string optname(argv[index]);
			if (optname[0] != '-') { break; } /* not starting with "-" => mainfile */
			if (optname.length() != 2) { throw err; } /* one-character options only */
			index++; /* skip the option name */

			switch (optname[1]) {
				case 'c':
					if (index >= argc) { throw err; } /* missing option value */
					this->cfgfile = argv[index];
#ifdef VERBOSE
					printf("cfgfile: %s\n", argv[index]);
#endif
					index++; /* skip the option value */
				break;

				case 'd':
					if (index >= argc) { throw err; } /* missing option value */
					v8::Debug::EnableAgent("v8cgi", atoi(argv[index]));
#ifdef VERBOSE
					printf("port: %s\n", argv[index]);
#endif
					index++; /* skip the option value */
				break;

				case 'h':
					printf(v8cgi_usage);
					printf("\n");
				break;

				case 'v':
					printf("v8cgi version %s", STRING(VERSION));
					printf("\n");
				break;

				default:
					throw err;
				break;
			}

		}

		if (index < argc) {
			/* argv[index] is the program file */
			this->mainfile = argv[index];
			/* expand mainfile to absolute path */
			if (!path_isabsolute(this->mainfile)) {
				std::string tmp = path_getcwd();
				tmp += "/";
				tmp += this->mainfile;
				this->mainfile = path_normalize(this->mainfile);
			}
			index++; /* skip over the program_file */
		}

		/* all the rest of the arguments are arguments to the program_file */
		for (; index < argc; ++index) {
#ifdef VERBOSE
			printf("program_arg: %s\n", argv[index]);
#endif
			this->mainfile_args.push_back(std::string(argv[index]));
		}
	}
};

#ifdef FASTCGI
	/**
	 * This is true only after we receive a signal to terminate
	 */
	void handle_sigterm(int param) {
		FCGI_SetExitStatus(0);
		exit(0);
 	}

	void handle_sigusr1(int param) {
		FCGI_SetExitStatus(0);
		exit(0);
	}
#endif

extern char ** environ;

int main(int argc, char ** argv) {
	int result = 0;
	v8cgi_CGI cgi;
	result = cgi.init(argc, argv);
	if (result) { exit(result); }

#ifdef FASTCGI
	signal(SIGTERM, handle_sigterm);
	signal(SIGUSR1, handle_sigusr1);
	/**
	 * FastCGI main loop
	 */
	while (FCGI_Accept() >= 0) {
		cgi.fromEnvVars();
#endif

		result = cgi.execute(environ);

#ifdef FASTCGI
		FCGI_SetExitStatus(result);
	}
#endif

	return result;
}
<|endoftext|>


<commit_before>#include "view.hpp"
#include "system.hpp"
#include "model/ply.hpp"
#include "model/obj.hpp"

#include <iostream>
#include <sstream>
#include <math.h>

#define GLFW_INCLUDE_NONE
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>

namespace View {
	bool view::setProg(std::atomic_bool &alive,
			const char *vert_fname, const char *frag_fname) {
		if(!alive) {
			return false;
		}
		//if(ids[e_id_prog]) glDeleteProgram(ids[e_id_prog]);
		ids[e_id_prog] = glCreateProgram();
		if(!link(vert_fname, frag_fname, ids[e_id_prog], errors)) {
			errors.emplace_back("Could not compile/link shader(s).");
			return alive = false;
		}
		auto mat_model = glGetUniformLocation(ids[e_id_prog], "model"),
			 mat_view = glGetUniformLocation(ids[e_id_prog], "view"),
			 mat_proj = glGetUniformLocation(ids[e_id_prog], "proj");
		if(mat_model == -1) {
			errors.emplace_back("Could not find uniform 'model'");
			return alive = false;
		} else {
			ids[e_id_model] = mat_model;
		}
		if(mat_view == -1) {
			errors.emplace_back("Could not find uniform 'view'");
			return alive = false;
		} else {
			ids[e_id_view] = mat_view;
		}
		if(mat_proj == -1) {
			errors.emplace_back("Could not find uniform 'view'");
			return alive = false;
		} else {
			ids[e_id_proj] = mat_proj;
		}
		glUseProgram(ids[e_id_prog]);
		return true;
	}

	void view::setUniforms(void) {
		int w, h;
		glfwGetFramebufferSize(win, &w, &h);
		float mag = float(1/tan(fov*M_PI/180));
		float mat_proj[]{
				mag, 0, 0, 0, 0, mag, 0, 0,
				0, 0, (far+near)/(far-near), -1,
				0, 0, 2*far*near/(far-near), 0
		};
		glUniformMatrix4fv(ids[e_id_proj], 1, GL_TRUE, mat_proj);

		float ct = cos(-theta*1.5), st = sin(-theta*1.5),
			  cp = cos(-phi), sp = sin(-phi);
		float mat_model[]{
				    ct,  0,    -st, 0,
				-sp*st, cp, -sp*ct, 0,
				 cp*st, sp,  cp*ct, 0,
				     0,  0,      0, 1
		}, mat_view[]{
				1, 0, 0, 0,
				0, 1, 0, 0,
				0, 0, 1, 0,
				0, 0, 2, 1
		};

		glUniformMatrix4fv(ids[e_id_model], 1, GL_TRUE, mat_model);
		glUniformMatrix4fv(ids[e_id_view], 1, GL_FALSE, mat_view);
	}

	void view::redraw() {
		static constexpr const unsigned int
			offset = 3*sizeof(float),
			stride = offset,
			//stride = 2*offset,
			bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
		setUniforms();
		glClearColor(0.5,0.5,0.5,1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glBindBuffer(GL_ARRAY_BUFFER, ids[e_id_vbuf]);

		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT,
				GL_FALSE, stride, nullptr);

 		/*glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 3, GL_FLOAT,
				GL_FALSE, stride, (void*) offset);*/

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ids[e_id_fbuf]);
		glDrawElements(GL_TRIANGLES, nTriangles*3,
				GL_UNSIGNED_INT, nullptr);

		//glDisableVertexAttribArray(1);
		glDisableVertexAttribArray(0);
		glfwSwapBuffers(win);
	}

	bool view::poll(std::atomic_bool &alive) {
		if(alive && win) {
			glfwMakeContextCurrent(win);
			glfwPollEvents();
		} else {
			return alive = false;
		}
		if(glfwWindowShouldClose(win)) {
			return alive = false;
		}
		return alive;
	}
	bool view::init(std::atomic_bool &alive) {
		if(!alive) {
			return false;
		}
		glfwSetWindowSizeCallback(win,
			[](GLFWwindow*, int w, int h){
				glViewport(0, 0, w, h);
			}
		);
		glfwSetErrorCallback(
			[] (int, const char *szErr) {
				std::cout << szErr << std::endl;
			});
		return alive;
	}

	bool view::run(std::atomic_bool &alive) {
		if(alive && win && !glfwWindowShouldClose(win)) {
			glfwMakeContextCurrent(win);
			redraw();
		}
		return alive;
	}
	view::view(std::atomic_bool &alive) {
		if(!alive) {
			return;
		}
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
		glfwWindowHint(GLFW_SAMPLES, 4);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

		if(!(win = glfwCreateWindow(680, 680, "View", NULL, NULL))) {
			errors.emplace_back("Could not create window.");
			alive = false;
			return;
		}

		glfwMakeContextCurrent(win);
		if(gl3wInit()) {
			errors.emplace_back("Could not initialize gl3w.");
			alive = false;
			return;
		}

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_MULTISAMPLE);
		glEnable(GL_POLYGON_SMOOTH);
		glHint(GL_POLYGON_SMOOTH, GL_NICEST);

		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);

		glGenVertexArrays(1, &ids[e_id_va]);
		glBindVertexArray(ids[e_id_va]);
	}
	view::~view(void) {
		if(ids[e_id_prog]) {
			glDeleteProgram(ids[e_id_prog]);
		}
		glfwDestroyWindow(win);
	}
}
<commit_msg>Darkened background to make model easier to see<commit_after>#include "view.hpp"
#include "system.hpp"
#include "model/ply.hpp"
#include "model/obj.hpp"

#include <iostream>
#include <sstream>
#include <math.h>

#define GLFW_INCLUDE_NONE
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>

namespace View {
	bool view::setProg(std::atomic_bool &alive,
			const char *vert_fname, const char *frag_fname) {
		if(!alive) {
			return false;
		}
		//if(ids[e_id_prog]) glDeleteProgram(ids[e_id_prog]);
		ids[e_id_prog] = glCreateProgram();
		if(!link(vert_fname, frag_fname, ids[e_id_prog], errors)) {
			errors.emplace_back("Could not compile/link shader(s).");
			return alive = false;
		}
		auto mat_model = glGetUniformLocation(ids[e_id_prog], "model"),
			 mat_view = glGetUniformLocation(ids[e_id_prog], "view"),
			 mat_proj = glGetUniformLocation(ids[e_id_prog], "proj");
		if(mat_model == -1) {
			errors.emplace_back("Could not find uniform 'model'");
			return alive = false;
		} else {
			ids[e_id_model] = mat_model;
		}
		if(mat_view == -1) {
			errors.emplace_back("Could not find uniform 'view'");
			return alive = false;
		} else {
			ids[e_id_view] = mat_view;
		}
		if(mat_proj == -1) {
			errors.emplace_back("Could not find uniform 'view'");
			return alive = false;
		} else {
			ids[e_id_proj] = mat_proj;
		}
		glUseProgram(ids[e_id_prog]);
		return true;
	}

	void view::setUniforms(void) {
		int w, h;
		glfwGetFramebufferSize(win, &w, &h);
		float mag = float(1/tan(fov*M_PI/180));
		float mat_proj[]{
				mag, 0, 0, 0, 0, mag, 0, 0,
				0, 0, (far+near)/(far-near), -1,
				0, 0, 2*far*near/(far-near), 0
		};
		glUniformMatrix4fv(ids[e_id_proj], 1, GL_TRUE, mat_proj);

		float ct = cos(-theta*1.5), st = sin(-theta*1.5),
			  cp = cos(-phi), sp = sin(-phi);
		float mat_model[]{
				    ct,  0,    -st, 0,
				-sp*st, cp, -sp*ct, 0,
				 cp*st, sp,  cp*ct, 0,
				     0,  0,      0, 1
		}, mat_view[]{
				1, 0, 0, 0,
				0, 1, 0, 0,
				0, 0, 1, 0,
				0, 0, 2, 1
		};

		glUniformMatrix4fv(ids[e_id_model], 1, GL_TRUE, mat_model);
		glUniformMatrix4fv(ids[e_id_view], 1, GL_FALSE, mat_view);
	}

	void view::redraw() {
		static constexpr const unsigned int
			offset = 3*sizeof(float),
			stride = offset,
			//stride = 2*offset,
			bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
		setUniforms();
		glClearColor(0.25,0.25,0.25,1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glBindBuffer(GL_ARRAY_BUFFER, ids[e_id_vbuf]);

		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT,
				GL_FALSE, stride, nullptr);

 		/*glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 3, GL_FLOAT,
				GL_FALSE, stride, (void*) offset);*/

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ids[e_id_fbuf]);
		glDrawElements(GL_TRIANGLES, nTriangles*3,
				GL_UNSIGNED_INT, nullptr);

		//glDisableVertexAttribArray(1);
		glDisableVertexAttribArray(0);
		glfwSwapBuffers(win);
	}

	bool view::poll(std::atomic_bool &alive) {
		if(alive && win) {
			glfwMakeContextCurrent(win);
			glfwPollEvents();
		} else {
			return alive = false;
		}
		if(glfwWindowShouldClose(win)) {
			return alive = false;
		}
		return alive;
	}
	bool view::init(std::atomic_bool &alive) {
		if(!alive) {
			return false;
		}
		glfwSetWindowSizeCallback(win,
			[](GLFWwindow*, int w, int h){
				glViewport(0, 0, w, h);
			}
		);
		glfwSetErrorCallback(
			[] (int, const char *szErr) {
				std::cout << szErr << std::endl;
			});
		return alive;
	}

	bool view::run(std::atomic_bool &alive) {
		if(alive && win && !glfwWindowShouldClose(win)) {
			glfwMakeContextCurrent(win);
			redraw();
		}
		return alive;
	}
	view::view(std::atomic_bool &alive) {
		if(!alive) {
			return;
		}
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
		glfwWindowHint(GLFW_SAMPLES, 4);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

		if(!(win = glfwCreateWindow(680, 680, "View", NULL, NULL))) {
			errors.emplace_back("Could not create window.");
			alive = false;
			return;
		}

		glfwMakeContextCurrent(win);
		if(gl3wInit()) {
			errors.emplace_back("Could not initialize gl3w.");
			alive = false;
			return;
		}

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_MULTISAMPLE);
		glEnable(GL_POLYGON_SMOOTH);
		glHint(GL_POLYGON_SMOOTH, GL_NICEST);

		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);

		glGenVertexArrays(1, &ids[e_id_va]);
		glBindVertexArray(ids[e_id_va]);
	}
	view::~view(void) {
		if(ids[e_id_prog]) {
			glDeleteProgram(ids[e_id_prog]);
		}
		glfwDestroyWindow(win);
	}
}
<|endoftext|>


<commit_before>#include "UEPyWorld.h"

#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"
#include "EngineUtils.h"
#include "Kismet/GameplayStatics.h"
#include "Runtime/CoreUObject/Public/UObject/UObjectIterator.h"
#if WITH_EDITOR
#include "Editor/UnrealEd/Public/EditorActorFolders.h"
#endif

PyObject *py_ue_world_exec(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *command;
	if (!PyArg_ParseTuple(args, "s:world_exec", &command))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	if (world->Exec(world, UTF8_TO_TCHAR(command)))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;

}

PyObject *py_ue_quit_game(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	// no need to support multiple controllers
	APlayerController *controller = world->GetFirstPlayerController();
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve the first controller");

#if ENGINE_MINOR_VERSION > 20
	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit, false);
#else
	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit);
#endif

	Py_RETURN_NONE;
}

PyObject *py_ue_get_world_type(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return PyLong_FromUnsignedLong(world->WorldType);
}

PyObject *py_ue_play(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->BeginPlay();

	Py_RETURN_NONE;
}

// mainly used for testing
PyObject *py_ue_world_tick(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	float delta_time;
	PyObject *py_increase_fc = nullptr;
	if (!PyArg_ParseTuple(args, "f|O:world_tick", &delta_time, &py_increase_fc))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->Tick(LEVELTICK_All, delta_time);

	if (py_increase_fc && PyObject_IsTrue(py_increase_fc))
		GFrameCounter++;

	Py_RETURN_NONE;
}

PyObject *py_ue_all_objects(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TObjectIterator<UObject> Itr; Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		if (u_obj->GetWorld() != world)
			continue;
		ue_PyUObject *py_obj = ue_get_python_uobject(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);
	}
	return ret;
}

PyObject *py_ue_all_actors(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TActorIterator<AActor> Itr(world); Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		ue_PyUObject *py_obj = ue_get_python_uobject(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}

	return ret;
}

PyObject *py_ue_find_object(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *name;
	if (!PyArg_ParseTuple(args, "s:find_object", &name))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = FindObject<UObject>(world->GetOutermost(), UTF8_TO_TCHAR(name));

	if (!u_object)
		return PyErr_Format(PyExc_Exception, "unable to find object %s", name);

	Py_RETURN_UOBJECT(u_object);
}

PyObject *py_ue_get_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	Py_RETURN_UOBJECT(world);
}

PyObject *py_ue_get_game_viewport(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UGameViewportClient *viewport_client = world->GetGameViewport();
	if (!viewport_client)
		return PyErr_Format(PyExc_Exception, "world has no GameViewportClient");

	Py_RETURN_UOBJECT((UObject *)viewport_client);
}

PyObject *py_ue_has_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (ue_get_uworld(self))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

PyObject *py_ue_set_view_target(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *py_obj;
	int controller_id = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_view_target", &py_obj, &controller_id))
	{
		return NULL;
	}

	AActor *actor = ue_py_check_type<AActor>(py_obj);
	if (!actor)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an actor");
	}

	APlayerController *controller = UGameplayStatics::GetPlayerController(world, controller_id);
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve controller %d", controller_id);

	controller->SetViewTarget(actor);

	Py_RETURN_NONE;

}

PyObject *py_ue_get_world_delta_seconds(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return Py_BuildValue("f", UGameplayStatics::GetWorldDeltaSeconds(world));
}

PyObject *py_ue_get_levels(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (ULevel *level : world->GetLevels())
	{
		ue_PyUObject *py_obj = ue_get_python_uobject(level);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}
	return ret;
}

PyObject *py_ue_get_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = world->GetCurrentLevel();
	if (!level)
		Py_RETURN_NONE;

	Py_RETURN_UOBJECT(level);
}

PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_level;

	if (!PyArg_ParseTuple(args, "O", &py_level))
		return nullptr;

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = ue_py_check_type<ULevel>(py_level);
	if (!level)
		return PyErr_Format(PyExc_Exception, "argument is not a ULevel");

	if (world->SetCurrentLevel(level))
		Py_RETURN_TRUE;

	Py_RETURN_FALSE;
}

#if WITH_EDITOR
PyObject *py_ue_get_level_script_blueprint(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	ULevel *level = ue_py_check_type<ULevel>(self);
	if (!level)
	{
		return PyErr_Format(PyExc_Exception, "uobject is not a ULevel");
	}

	Py_RETURN_UOBJECT((UObject*)level->GetLevelScriptBlueprint());
}

PyObject *py_ue_world_create_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	if (!PyArg_ParseTuple(args, "s:world_create_folder", &path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));

	FActorFolders::Get().CreateFolder(*world, FolderPath);

	Py_RETURN_NONE;
}

PyObject *py_ue_world_delete_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	if (!PyArg_ParseTuple(args, "s:world_delete_folder", &path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));

	FActorFolders::Get().DeleteFolder(*world, FolderPath);

	Py_RETURN_NONE;
}

PyObject *py_ue_world_rename_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	char *new_path;
	if (!PyArg_ParseTuple(args, "ss:world_rename_folder", &path, &new_path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));
	FName NewFolderPath = FName(UTF8_TO_TCHAR(new_path));

	if (FActorFolders::Get().RenameFolderInWorld(*world, FolderPath, NewFolderPath))
		Py_RETURN_TRUE;

	Py_RETURN_FALSE;
}

PyObject *py_ue_world_folders(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	const TMap<FName, FActorFolderProps> &Folders = FActorFolders::Get().GetFolderPropertiesForWorld(*world);

	PyObject *py_list = PyList_New(0);

	TArray<FName> FolderNames;
	Folders.GenerateKeyArray(FolderNames);

	for (FName FolderName : FolderNames)
	{
		PyObject *py_str = PyUnicode_FromString(TCHAR_TO_UTF8(*FolderName.ToString()));
		PyList_Append(py_list, py_str);
		Py_DECREF(py_str);
	}

	return py_list;
}
#endif
<commit_msg>fixed non editor build<commit_after>#include "UEPyWorld.h"

#include "Runtime/Engine/Classes/Kismet/KismetSystemLibrary.h"
#include "EngineUtils.h"
#include "Kismet/GameplayStatics.h"
#include "Runtime/CoreUObject/Public/UObject/UObjectIterator.h"
#if WITH_EDITOR
#include "Editor/UnrealEd/Public/EditorActorFolders.h"
#endif

PyObject *py_ue_world_exec(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *command;
	if (!PyArg_ParseTuple(args, "s:world_exec", &command))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	if (world->Exec(world, UTF8_TO_TCHAR(command)))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;

}

PyObject *py_ue_quit_game(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	// no need to support multiple controllers
	APlayerController *controller = world->GetFirstPlayerController();
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve the first controller");

#if ENGINE_MINOR_VERSION > 20
	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit, false);
#else
	UKismetSystemLibrary::QuitGame(world, controller, EQuitPreference::Quit);
#endif

	Py_RETURN_NONE;
}

PyObject *py_ue_get_world_type(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return PyLong_FromUnsignedLong(world->WorldType);
}

PyObject *py_ue_play(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->BeginPlay();

	Py_RETURN_NONE;
}

// mainly used for testing
PyObject *py_ue_world_tick(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	float delta_time;
	PyObject *py_increase_fc = nullptr;
	if (!PyArg_ParseTuple(args, "f|O:world_tick", &delta_time, &py_increase_fc))
	{
		return nullptr;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	world->Tick(LEVELTICK_All, delta_time);

	if (py_increase_fc && PyObject_IsTrue(py_increase_fc))
		GFrameCounter++;

	Py_RETURN_NONE;
}

PyObject *py_ue_all_objects(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TObjectIterator<UObject> Itr; Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		if (u_obj->GetWorld() != world)
			continue;
		ue_PyUObject *py_obj = ue_get_python_uobject(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);
	}
	return ret;
}

PyObject *py_ue_all_actors(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (TActorIterator<AActor> Itr(world); Itr; ++Itr)
	{
		UObject *u_obj = *Itr;
		ue_PyUObject *py_obj = ue_get_python_uobject(u_obj);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}

	return ret;
}

PyObject *py_ue_find_object(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *name;
	if (!PyArg_ParseTuple(args, "s:find_object", &name))
	{
		return NULL;
	}

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UObject *u_object = FindObject<UObject>(world->GetOutermost(), UTF8_TO_TCHAR(name));

	if (!u_object)
		return PyErr_Format(PyExc_Exception, "unable to find object %s", name);

	Py_RETURN_UOBJECT(u_object);
}

PyObject *py_ue_get_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	Py_RETURN_UOBJECT(world);
}

PyObject *py_ue_get_game_viewport(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	UGameViewportClient *viewport_client = world->GetGameViewport();
	if (!viewport_client)
		return PyErr_Format(PyExc_Exception, "world has no GameViewportClient");

	Py_RETURN_UOBJECT((UObject *)viewport_client);
}

PyObject *py_ue_has_world(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (ue_get_uworld(self))
		Py_RETURN_TRUE;
	Py_RETURN_FALSE;
}

PyObject *py_ue_set_view_target(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *py_obj;
	int controller_id = 0;
	if (!PyArg_ParseTuple(args, "O|i:set_view_target", &py_obj, &controller_id))
	{
		return NULL;
	}

	AActor *actor = ue_py_check_type<AActor>(py_obj);
	if (!actor)
	{
		return PyErr_Format(PyExc_Exception, "argument is not an actor");
	}

	APlayerController *controller = UGameplayStatics::GetPlayerController(world, controller_id);
	if (!controller)
		return PyErr_Format(PyExc_Exception, "unable to retrieve controller %d", controller_id);

	controller->SetViewTarget(actor);

	Py_RETURN_NONE;

}

PyObject *py_ue_get_world_delta_seconds(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	return Py_BuildValue("f", UGameplayStatics::GetWorldDeltaSeconds(world));
}

PyObject *py_ue_get_levels(ue_PyUObject * self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	PyObject *ret = PyList_New(0);

	for (ULevel *level : world->GetLevels())
	{
		ue_PyUObject *py_obj = ue_get_python_uobject(level);
		if (!py_obj)
			continue;
		PyList_Append(ret, (PyObject *)py_obj);

	}
	return ret;
}

PyObject *py_ue_get_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = world->GetCurrentLevel();
	if (!level)
		Py_RETURN_NONE;

	Py_RETURN_UOBJECT(level);
}

PyObject *py_ue_set_current_level(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	PyObject *py_level;

	if (!PyArg_ParseTuple(args, "O", &py_level))
		return nullptr;

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	ULevel *level = ue_py_check_type<ULevel>(py_level);
	if (!level)
		return PyErr_Format(PyExc_Exception, "argument is not a ULevel");

#if WITH_EDITOR

	if (world->SetCurrentLevel(level))
		Py_RETURN_TRUE;
#endif

	Py_RETURN_FALSE;
}

#if WITH_EDITOR
PyObject *py_ue_get_level_script_blueprint(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	ULevel *level = ue_py_check_type<ULevel>(self);
	if (!level)
	{
		return PyErr_Format(PyExc_Exception, "uobject is not a ULevel");
	}

	Py_RETURN_UOBJECT((UObject*)level->GetLevelScriptBlueprint());
}

PyObject *py_ue_world_create_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	if (!PyArg_ParseTuple(args, "s:world_create_folder", &path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));

	FActorFolders::Get().CreateFolder(*world, FolderPath);

	Py_RETURN_NONE;
}

PyObject *py_ue_world_delete_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	if (!PyArg_ParseTuple(args, "s:world_delete_folder", &path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));

	FActorFolders::Get().DeleteFolder(*world, FolderPath);

	Py_RETURN_NONE;
}

PyObject *py_ue_world_rename_folder(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	char *path;
	char *new_path;
	if (!PyArg_ParseTuple(args, "ss:world_rename_folder", &path, &new_path))
		return nullptr;

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	FName FolderPath = FName(UTF8_TO_TCHAR(path));
	FName NewFolderPath = FName(UTF8_TO_TCHAR(new_path));

	if (FActorFolders::Get().RenameFolderInWorld(*world, FolderPath, NewFolderPath))
		Py_RETURN_TRUE;

	Py_RETURN_FALSE;
}

PyObject *py_ue_world_folders(ue_PyUObject *self, PyObject * args)
{

	ue_py_check(self);

	if (!FActorFolders::IsAvailable())
		return PyErr_Format(PyExc_Exception, "FActorFolders is not available");

	UWorld *world = ue_get_uworld(self);
	if (!world)
		return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject");

	const TMap<FName, FActorFolderProps> &Folders = FActorFolders::Get().GetFolderPropertiesForWorld(*world);

	PyObject *py_list = PyList_New(0);

	TArray<FName> FolderNames;
	Folders.GenerateKeyArray(FolderNames);

	for (FName FolderName : FolderNames)
	{
		PyObject *py_str = PyUnicode_FromString(TCHAR_TO_UTF8(*FolderName.ToString()));
		PyList_Append(py_list, py_str);
		Py_DECREF(py_str);
	}

	return py_list;
}
#endif
<|endoftext|>