Commit message: .
CVE: CVE-2019-13568
CWE: CWE-787
Vulnerability description: CImg through 2.6.7 has a heap-based buffer overflow in _load_bmp in CImg.h because of erroneous memory allocation for a malformed BMP image.

Project: CImg
File: CImg.h

    **/
    inline char *strellipsize(char *const str, const unsigned int l=64,
                              const bool is_ending=true) {
      if (!str) return str;
      const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
      if (ls<=nl) return str;
      if (is_ending) std::strcpy(str + nl - 5,"(...)");
      else {
        const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
        std::strcpy(str + ll,"(...)");
        std::memmove(str + ll + 5,str + ls - lr,lr);
      }
      str[nl] = 0;
      return str;

Project: CImg
File: CImg.h

      static bool is_nan(const char) { return false; }

Project: CImg
File: CImg.h

    //! Test if image height is equal to specified value.
    bool is_sameY(const CImgDisplay& disp) const {
      return is_sameY(disp._height);

Project: CImg
File: CImg.h

    template<typename tx, typename ty, typename tc>
    CImg<T>& draw_grid(const CImg<tx>& values_x, const CImg<ty>& values_y,
                       const tc *const color, const float opacity=1,
                       const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) {
      if (is_empty()) return *this;
      if (values_x) cimg_foroff(values_x,x) {
          const int xi = (int)values_x[x];
          if (xi>=0 && xi<width()) draw_line(xi,0,xi,_height - 1,color,opacity,pattern_x);
        }
      if (values_y) cimg_foroff(values_y,y) {
          const int yi = (int)values_y[y];
          if (yi>=0 && yi<height()) draw_line(0,yi,_width - 1,yi,color,opacity,pattern_y);
        }
      return *this;

Project: CImg
File: CImg.h

    **/
    static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
      CImg<T> r(1,3); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
      return r;

Project: CImg
File: CImg.h

    //! Load image from a PANDORE-5 file \newinstance.
    static CImg<T> get_load_pandore(const char *const filename) {
      return CImg<T>().load_pandore(filename);

Project: CImg
File: CImg.h

      static const char* string() { static const char *const s = "unsigned short"; return s; }

Project: CImg
File: CImg.h


      static double mp_median(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        switch (i_end - 3) {
        case 1 : return _mp_arg(3);
        case 2 : return cimg::median(_mp_arg(3),_mp_arg(4));
        case 3 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5));
        case 5 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7));
        case 7 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9));
        case 9 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9),
                                     _mp_arg(10),_mp_arg(11));
        case 13 : return cimg::median(_mp_arg(3),_mp_arg(4),_mp_arg(5),_mp_arg(6),_mp_arg(7),_mp_arg(8),_mp_arg(9),
                                      _mp_arg(10),_mp_arg(11),_mp_arg(12),_mp_arg(13),_mp_arg(14),_mp_arg(15));
        }
        CImg<doubleT> vals(i_end - 3);
        double *p = vals.data();
        for (unsigned int i = 3; i<i_end; ++i) *(p++) = _mp_arg(i);
        return vals.median();

Project: CImg
File: CImg.h

    //! Return the factorial of n
    inline double factorial(const int n) {
      if (n<0) return cimg::type<double>::nan();
      if (n<2) return 1;
      double res = 2;
      for (int i = 3; i<=n; ++i) res*=i;
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator/(const CImg<t>& img) const {
      return (*this)*img.get_invert();

Project: CImg
File: CImg.h

    //! Load sub-images of a .cimg file \overloading.
    CImg<T>& load_cimg(std::FILE *const file,
                       const unsigned int n0, const unsigned int n1,
                       const unsigned int x0, const unsigned int y0,
                       const unsigned int z0, const unsigned int c0,
                       const unsigned int x1, const unsigned int y1,
                       const unsigned int z1, const unsigned int c1,
                       const char axis='z', const float align=0) {
      CImgList<T> list;
      list.load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1);
      if (list._width==1) return list[0].move_to(*this);
      return assign(list.get_append(axis,align));

Project: CImg
File: CImg.h

      }
      static bool is_nan(const float val) { // Custom version that works with '-ffast-math'
        if (sizeof(float)==4) {
          unsigned int u;
          std::memcpy(&u,&val,sizeof(float));
          return (u&0x7fffffff)>0x7f800000;
        }
#ifdef isnan
        return (bool)isnan(val);
#else
        return !(val==val);
#endif

Project: CImg
File: CImg.h


    CImgDisplay& close() {
      if (is_empty() || _is_closed) return *this;
      _is_closed = true;
      if (_is_fullscreen) _desinit_fullscreen();
      ShowWindow(_window,SW_HIDE);
      _window_x = _window_y = 0;
      return *this;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to sRGB color spaces.
    CImg<T>& RGBtosRGB() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32))
      cimg_rofoff(*this,off) {
        const Tfloat
          val = (Tfloat)_data[off]/255,
          sval = (Tfloat)(val<=0.0031308f?val*12.92f:1.055f*std::pow(val,0.416667f) - 0.055f);
        _data[off] = (T)cimg::cut(sval*255,0,255);
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_list_set_joff(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        const int
          ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y],
          oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c];
        const longT
          off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3),
          whds = (longT)img.size();
        const double val = _mp_arg(1);
        if (off>=0 && off<whds) img[off] = (T)val;
        return val;

Project: CImg
File: CImg.h


      static double mp_vector_set_off(_cimg_math_parser& mp) {
        const unsigned int
          ptr = (unsigned int)mp.opcode[2] + 1,
          siz = (unsigned int)mp.opcode[3];
        const int off = (int)_mp_arg(4);
        if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5);
        return _mp_arg(5);

Project: CImg
File: CImg.h

    //! Wait for any event occuring either on the display \c disp1 or \c disp2.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
      disp1._is_event = disp2._is_event = false;
      while ((!disp1._is_closed || !disp2._is_closed) &&
             !disp1._is_event && !disp2._is_event) wait_all();

Project: CImg
File: CImg.h


    Tfloat _cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = cimg::type<float>::is_nan(fx)?0:cimg::mod(fx,(float)_width);
      const int
        x = (int)nfx;
      const float
        dx = nfx - x;
      const int
        px = cimg::mod(x - 1,width()), nx = cimg::mod(x + 1,width()), ax = cimg::mod(x + 2,width());
      const Tfloat
        Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),
        In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);
      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this).cross(img);

Project: CImg
File: CImg.h

      return res;
    }

    //! Return a shared sublist \newinstance.
    const CImgList<T> get_shared_images(const unsigned int pos0, const unsigned int pos1) const {
      if (pos0>pos1 || pos1>=_width)
        throw CImgArgumentException(_cimglist_instance
                                    "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.",
                                    cimglist_instance,
                                    pos0,pos1);

Project: CImg
File: CImg.h

    // (Original code by Haz-Edine Assemlal).
    CImg<T>& load_minc2(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_minc2(): Specified filename is (null).",
                                    cimg_instance);
#ifndef cimg_use_minc2
      return load_other(filename);
#else
      minc::minc_1_reader rdr;
      rdr.open(filename);
      assign(rdr.ndim(1)?rdr.ndim(1):1,
             rdr.ndim(2)?rdr.ndim(2):1,
             rdr.ndim(3)?rdr.ndim(3):1,
             rdr.ndim(4)?rdr.ndim(4):1);
      if (cimg::type<T>::string()==cimg::type<unsigned char>::string())
        rdr.setup_read_byte();
      else if (cimg::type<T>::string()==cimg::type<int>::string())
        rdr.setup_read_int();
      else if (cimg::type<T>::string()==cimg::type<double>::string())
        rdr.setup_read_double();
      else
        rdr.setup_read_float();
      minc::load_standard_volume(rdr,this->_data);
      return *this;
#endif

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \newinstance.
    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                     const T& val6) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6);

Project: CImg
File: CImg.h

    //! Construct image with specified size and initialize pixel values from a memory buffer \overloading.
    CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y,
                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
      const size_t siz = (size_t)size_x*size_y*size_z*size_c;
      if (!values || !siz) return assign();
      if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); }
      else {
	if (!_is_shared) {
	  if (values + siz<_data || values>=_data + size()) assign();
	  else cimg::warn(_cimg_instance
                          "assign(): Shared image instance has overlapping memory.",
                          cimg_instance);
	}
	_width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true;
	_data = const_cast<T*>(values);
      }
      return *this;

Project: CImg
File: CImg.h

    //! Autocrop image region, regarding the specified background value \newinstance.
    CImg<T> get_autocrop(const T& value, const char *const axes="czyx") const {
      return (+*this).autocrop(value,axes);

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImgList<to>& opacities,
                           const unsigned int render_type=4,
                           const bool is_double_sided=false, const float focale=700,
                           const float lightx=0, const float lighty=0, const float lightz=-5e8,
                           const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                           const float g_opacity=1) {
      return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type,
                           is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,CImg<floatT>::empty());

Project: CImg
File: CImg.h

    template<typename T>
    inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8, T val9, T val10, T val11,
                    T val12) {
      T tmp = std::min(val1,val7);
      val7 = std::max(val1,val7); val1 = tmp; tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp;
      tmp = std::min(val3,val4);  val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val5,val8);
      val8 = std::max(val5,val8); val5 = tmp; tmp = std::min(val0,val12); val12 = std::max(val0,val12);
      val0 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val0,val1);
      val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val2,val3); val3 = std::max(val2,val3); val2 = tmp;
      tmp = std::min(val4,val6);  val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val8,val11);
      val11 = std::max(val8,val11); val8 = tmp; tmp = std::min(val7,val12); val12 = std::max(val7,val12); val7 = tmp;
      tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val0,val2);
      val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp;
      tmp = std::min(val10,val11); val11 = std::max(val10,val11); val10 = tmp; tmp = std::min(val1,val4);
      val4 = std::max(val1,val4); val1 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp;
      tmp = std::min(val7,val8); val8 = std::max(val7,val8); val7 = tmp; val11 = std::min(val11,val12);
      tmp = std::min(val4,val9); val9 = std::max(val4,val9); val4 = tmp; tmp = std::min(val6,val10);
      val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4); val3 = tmp;
      tmp = std::min(val5,val6); val6 = std::max(val5,val6); val5 = tmp; val8 = std::min(val8,val9);
      val10 = std::min(val10,val11); tmp = std::min(val1,val7); val7 = std::max(val1,val7); val1 = tmp;
      tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; val3 = std::max(val1,val3);
      tmp = std::min(val4,val7); val7 = std::max(val4,val7); val4 = tmp; val8 = std::min(val8,val10);
      val5 = std::max(val0,val5); val5 = std::max(val2,val5); tmp = std::min(val6,val8); val8 = std::max(val6,val8);
      val5 = std::max(val3,val5); val7 = std::min(val7,val8); val6 = std::max(val4,tmp); tmp = std::min(val4,tmp);
      val5 = std::max(tmp,val5); val6 = std::min(val6,val7);
      return std::max(val5,val6);

Project: CImg
File: CImg.h

    template<typename t>
    CImgList<T>& operator=(const CImg<t>& img) {
      return assign(img);

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!img) return assign();
      CImg<T> tmp;
      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2,
                                                                           (img._height - 1)/2,
                                                                           (img._depth - 1)/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return render(nimg).paint();

Project: CImg
File: CImg.h

    **/
   T& atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimglist_instance
                                    "atNXYZ(): Empty instance.",
                                    cimglist_instance);

      return _atNXYZ(pos,x,y,z,c);

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_other(const char *const filename) {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_other(): Specified filename is (null).",
                                    cimg_instance);

      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      try { load_magick(filename); }
      catch (CImgException&) {
        try { load_imagemagick_external(filename); }
        catch (CImgException&) {
          try { load_graphicsmagick_external(filename); }
          catch (CImgException&) {
            try { load_cimg(filename); }
            catch (CImgException&) {
              try {
                cimg::fclose(cimg::fopen(filename,"rb"));
              } catch (CImgException&) {
                cimg::exception_mode(omode);
                throw CImgIOException(_cimg_instance
                                      "load_other(): Failed to open file '%s'.",
                                      cimg_instance,
                                      filename);
              }
              cimg::exception_mode(omode);
              throw CImgIOException(_cimg_instance
                                    "load_other(): Failed to recognize format of file '%s'.",
                                    cimg_instance,
                                    filename);
            }
          }
        }
      }
      cimg::exception_mode(omode);
      return *this;

Project: CImg
File: CImg.h

    //! Return hyperbolic arctangent of a value.
    inline double atanh(const double x) {
#if cimg_use_cpp11==1 && !defined(_MSC_VER)
      return std::atanh(x);
#else
      return 0.5*std::log((1. + x)/(1. - x));
#endif

Project: CImg
File: CImg.h

      CImg<floatT> *pI;

Project: CImg
File: CImg.h


      static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) {
        double &val = _mp_arg(1);
        return val = (double)((longT)val<<(unsigned int)_mp_arg(2));

Project: CImg
File: CImg.h

    **/
    CImgDisplay& resize(const int width, const int height, const bool force_redraw=true) {
      return assign(width,height,0,3,force_redraw);

Project: CImg
File: CImg.h


      unsigned int scalar6(const mp_func op,
                           const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
                           const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) {
        const unsigned int pos =
          arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1:
          arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2:
          arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3:
          arg4!=~0U && arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4:
          arg5!=~0U && arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5:
          arg6!=~0U && arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6:scalar();
        CImg<ulongT>::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);
        return pos;

Project: CImg
File: CImg.h

    //! Access to a pixel value \const.
    const T& operator()(const unsigned int x, const unsigned int y=0,
                        const unsigned int z=0, const unsigned int c=0) const {
      return const_cast<CImg<T>*>(this)->operator()(x,y,z,c);

Project: CImg
File: CImg.h

    //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm \newinstance.
    CImg<Tfloat> get_normalize() const {
      return CImg<Tfloat>(*this,false).normalize();

Project: CImg
File: CImg.h

    //! Save image as a .cimg file \overloading.
    const CImg<T>& save_cimg(std::FILE *const file, const bool is_compressed=false) const {
      CImgList<T>(*this,true).save_cimg(file,is_compressed);
      return *this;

Project: CImg
File: CImg.h

      static bool is_inf(const char) { return false; }

Project: CImg
File: CImg.h

    //! Pointwise min operator between instance image and a value \newinstance.
    CImg<T> get_min(const T& value) const {
      return (+*this).min(value);

Project: CImg
File: CImg.h


      static double mp_list_stats(_cimg_math_parser& mp) {
        const unsigned int
          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
          k = (unsigned int)mp.opcode[3];
        if (!mp.list_stats) mp.list_stats.assign(mp.listin._width);
        if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false);
        return mp.list_stats(ind,k);

Project: CImg
File: CImg.h


    inline const char* option(const char *const name, const int argc, const char *const *const argv,
                              const char *const defaut, const char *const usage=0) {
      return option(name,argc,argv,defaut,usage,false);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T> operator&(const t value) const {
      return (+*this)&=value;

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \newinstance.
    CImg<T> get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                     const T& val6, const T& val7, const T& val8, const T& val9) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);

Project: CImg
File: CImg.h

        return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }

Project: CImg
File: CImg.h

    **/
    CImg<T>& distance(const T& value, const unsigned int metric=2) {
      if (is_empty()) return *this;
      if (cimg::type<Tint>::string()!=cimg::type<T>::string()) // For datatype < int
        return CImg<Tint>(*this,false).distance((Tint)value,metric).
          cut((Tint)cimg::type<T>::min(),(Tint)cimg::type<T>::max()).move_to(*this);
      bool is_value = false;
      cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,(T)0:(T)std::max(0,99999999); // (avoid VC++ warning)
      if (!is_value) return fill(cimg::type<T>::max());
      switch (metric) {
      case 0 : return _distance_core(_distance_sep_cdt,_distance_dist_cdt);          // Chebyshev
      case 1 : return _distance_core(_distance_sep_mdt,_distance_dist_mdt);          // Manhattan
      case 3 : return _distance_core(_distance_sep_edt,_distance_dist_edt);          // Squared Euclidean
      default : return _distance_core(_distance_sep_edt,_distance_dist_edt).sqrt();  // Euclidean
      }
      return *this;

Project: CImg
File: CImg.h


      static double mp_eye(_cimg_math_parser& mp) {
        double *ptrd = &_mp_arg(1) + 1;
        const unsigned int k = (unsigned int)mp.opcode[2];
        CImg<doubleT>(ptrd,k,k,1,1,true).identity_matrix();
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Load sub-images of a .cimg file \newinstance.
    static CImg<T> get_load_cimg(std::FILE *const file,
                                 const unsigned int n0, const unsigned int n1,
                                 const unsigned int x0, const unsigned int y0,
                                 const unsigned int z0, const unsigned int c0,
                                 const unsigned int x1, const unsigned int y1,
                                 const unsigned int z1, const unsigned int c1,
                                 const char axis='z', const float align=0) {
      return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align);

Project: CImg
File: CImg.h

    **/
    bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length,
                         const bool remove_sequence=false) {
      if (keycodes_sequence && length) {
        const unsigned int
          *const ps_end = keycodes_sequence + length - 1,
          *const pk_end = (unsigned int*)_keys + 1 + 128 - length,
          k = *ps_end;
        for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) {
          if (*(pk++)==k) {
            bool res = true;
            const unsigned int *ps = ps_end, *pk2 = pk;
            for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++));
            if (res) {
              if (remove_sequence) std::memset((void*)(pk - 1),0,sizeof(unsigned int)*length);
              return true;
            }
          }
        }
      }
      return false;

Project: CImg
File: CImg.h

#if cimg_verbosity>=3
    T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
      const ulongT off = (ulongT)offset(x,y,z,c);
      if (off>=size())
        cimg::warn(_cimg_instance
                   "data(): Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].",
                   cimg_instance,
                   x,y,z,c,off);
      return _data + off;

Project: CImg
File: CImg.h

    //! Compute the Moore-Penrose pseudo-inverse of the instance image, viewed as a matrix \newinstance.
    CImg<Tfloat> get_pseudoinvert() const {
      CImg<Tfloat> U, S, V;
      SVD(U,S,V);
      const Tfloat tolerance = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*std::max(_width,_height)*S.max();
      cimg_forX(V,x) {
	const Tfloat s = S(x), invs = s>tolerance?1/s:0;
	cimg_forY(V,y) V(x,y)*=invs;
      }
      return V*U.transpose();

Project: CImg
File: CImg.h

      static const char* string() { static const char *const s = "bool"; return s; }

Project: CImg
File: CImg.h

    //! Convert pixel values from CMY to RGB color spaces \newinstance.
    CImg<Tuchar> get_CMYtoRGB() const {
      return CImg<Tuchar>(*this,false).CMYtoRGB();

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    const CImg<T>& display_object3d(const char *const title,
                                    const CImg<tp>& vertices,
                                    const CImgList<tf>& primitives,
                                    const CImgList<tc>& colors,
                                    const to& opacities,
                                    const bool centering=true,
                                    const int render_static=4, const int render_motion=1,
                                    const bool is_double_sided=true, const float focale=700,
                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,
                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                                    const bool display_axes=true, float *const pose_matrix=0,
                                    const bool exit_on_anykey=false) const {
      CImgDisplay disp;
      return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static,
			       render_motion,is_double_sided,focale,
                               light_x,light_y,light_z,specular_lightness,specular_shininess,
			       display_axes,pose_matrix,exit_on_anykey);

Project: CImg
File: CImg.h

    template<typename t>
    void _load_tiff_tiled_contig(TIFF *const tif, const uint16 samplesperpixel,
                                 const uint32 nx, const uint32 ny, const uint32 tw, const uint32 th) {
      t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif));
      if (buf) {
        for (unsigned int row = 0; row<ny; row+=th)
          for (unsigned int col = 0; col<nx; col+=tw) {
            if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
              _TIFFfree(buf); TIFFClose(tif);
              throw CImgIOException(_cimg_instance
                                    "load_tiff(): Invalid tile in file '%s'.",
                                    cimg_instance,
                                    TIFFFileName(tif));
            }
            const t *ptr = buf;
            for (unsigned int rr = row; rr<std::min((unsigned int)(row + th),(unsigned int)ny); ++rr)
              for (unsigned int cc = col; cc<std::min((unsigned int)(col + tw),(unsigned int)nx); ++cc)
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
                  (*this)(cc,rr,vv) = (T)(ptr[(rr - row)*th*samplesperpixel + (cc - col)*samplesperpixel + vv]);
          }
        _TIFFfree(buf);
      }

Project: CImg
File: CImg.h

    **/
    const CImg<T>& display_graph(CImgDisplay &disp,
                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
                                 const char *const labely=0, const double ymin=0, const double ymax=0,
                                 const bool exit_on_anykey=false) const {
      return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);

Project: CImg
File: CImg.h

    **/
    Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2;
      const float
        dx = fx - x;
      const Tfloat
        Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value),
        In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value);
      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to xyY color spaces.
    CImg<T>& RGBtoxyY(const bool use_D65=true) {
      return RGBtoXYZ(use_D65).XYZtoxyY();

Project: CImg
File: CImg.h

     **/
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
         const double value0, const double value1, ...):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,(size_t)size_x*size_y*size_z*size_c,double);

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to YUV color spaces.
    CImg<T>& RGBtoYUV() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoYUV(): Instance is not a RGB image.",
                                    cimg_instance);

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,16384))
      for (longT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N]/255,
          G = (Tfloat)p2[N]/255,
          B = (Tfloat)p3[N]/255,
          Y = 0.299f*R + 0.587f*G + 0.114f*B;
        p1[N] = (T)Y;
        p2[N] = (T)(0.492f*(B - Y));
        p3[N] = (T)(0.877*(R - Y));
      }
      return *this;

Project: CImg
File: CImg.h

    //! Return a reference to the maximum pixel value \const.
    const T& max() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max(): Empty instance.",
                                    cimg_instance);
      const T *ptr_max = _data;
      T max_value = *ptr_max;
      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
      return *ptr_max;

Project: CImg
File: CImg.h


    //! Remove first image.
    /**

Project: CImg
File: CImg.h

    **/
    T& atXY(const int x, const int y, const int z, const int c, const T& out_value) {
      return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, typename tz>
    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImgList<to>& opacities,
                           const unsigned int render_type,
                           const bool is_double_sided, const float focale,
                           const float lightx, const float lighty, const float lightz,
                           const float specular_lightness, const float specular_shininess,
                           const float g_opacity, CImg<tz>& zbuffer) {
      return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,
                            render_type,is_double_sided,focale,lightx,lighty,lightz,
                            specular_lightness,specular_shininess,g_opacity,1);

Project: CImg
File: CImg.h

    **/
    CImg<T> get_channels(const int c0, const int c1) const {
      return get_crop(0,0,0,c0,width() - 1,height() - 1,depth() - 1,c1);

Project: CImg
File: CImg.h


    inline char option(const char *const name, const int argc, const char *const *const argv,
                       const char defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const char res = s?*s:defaut;
      char tmp[8];
      *tmp = res; tmp[1] = 0;
      cimg::option(name,0,0,tmp,usage);
      return res;

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameXYZC(const CImg<t>& img) const {
      return is_sameXYZC(img._width,img._height,img._depth,img._spectrum);

Project: CImg
File: CImg.h

    template<typename t>
    CImgList<_cimg_Tt> operator,(const CImgList<t>& list) const {
      return CImgList<_cimg_Tt>(list,false).insert(*this,0);

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to>
    CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors, const CImg<to>& opacities,
                           const unsigned int render_type=4,
                           const bool is_double_sided=false, const float focale=700,
                           const float lightx=0, const float lighty=0, const float lightz=-5e8,
                           const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                           const float g_opacity=1) {
      return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type,
                           is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,CImg<floatT>::empty());

Project: CImg
File: CImg.h

    //! Resize image to triple-size, using the Scale3X algorithm \newinstance.
    CImg<T> get_resize_tripleXY() const {
#define _cimg_gs3x_for3(bound,i) \
 for (int i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound) - 1:1; \
      _n1##i<(int)(bound) || i==--_n1##i; \
      _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width)

#define _cimg_gs3x_for3x3(img,x,y,z,c,I,T) \
  _cimg_gs3x_for3((img)._height,y) for (int x = 0, \
   _p1##x = 0, \
   _n1##x = (int)( \
   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[3] = I[4] = (T)(img)(0,y,z,c)), \
   (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)),	\
   1>=(img)._width?(img).width() - 1:1); \
   (_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x; \
   I[0] = I[1], I[1] = I[2], \
   I[3] = I[4], I[4] = I[5], \
   I[6] = I[7], I[7] = I[8], \
   _p1##x = x++, ++_n1##x)

      if (is_empty()) return *this;
      CImg<T> res(3*_width,3*_height,_depth,_spectrum);
      CImg_3x3(I,T);
      cimg_forZC(*this,z,c) {
        T
          *ptrd1 = res.data(0,0,z,c),
          *ptrd2 = ptrd1 + res._width,
          *ptrd3 = ptrd2 + res._width;
        _cimg_gs3x_for3x3(*this,x,y,z,c,I,T) {
          if (Icp != Icn && Ipc != Inc) {
            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
            *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
            *(ptrd1++) = Icp==Inc?Inc:Icc;
            *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
            *(ptrd2++) = Icc;
            *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
            *(ptrd3++) = Ipc==Icn?Ipc:Icc;
            *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
            *(ptrd3++) = Icn==Inc?Inc:Icc;
          } else {
            *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
            *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
            *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to xyY color spaces \newinstance.
    CImg<Tfloat> get_RGBtoxyY(const bool use_D65=true) const {
      return CImg<Tfloat>(*this,false).RGBtoxyY(use_D65);

Project: CImg
File: CImg.h


    const CImg<T>& _save_bmp(std::FILE *const file, const char *const filename) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_bmp(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_bmp(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");
      if (_spectrum>3)
        cimg::warn(_cimg_instance
                   "save_bmp(): Instance is multispectral, only the three first channels will be saved in file '%s'.",
                   cimg_instance,
                   filename?filename:"(FILE*)");

      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
      CImg<ucharT> header(54,1,1,1,0);
      unsigned char align_buf[4] = { 0 };
      const unsigned int
        align = (4 - (3*_width)%4)%4,
        buf_size = (3*_width + align)*height(),
        file_size = 54 + buf_size;
      header[0] = 'B'; header[1] = 'M';
      header[0x02] = file_size&0xFF;
      header[0x03] = (file_size>>8)&0xFF;
      header[0x04] = (file_size>>16)&0xFF;
      header[0x05] = (file_size>>24)&0xFF;
      header[0x0A] = 0x36;
      header[0x0E] = 0x28;
      header[0x12] = _width&0xFF;
      header[0x13] = (_width>>8)&0xFF;
      header[0x14] = (_width>>16)&0xFF;
      header[0x15] = (_width>>24)&0xFF;
      header[0x16] = _height&0xFF;
      header[0x17] = (_height>>8)&0xFF;
      header[0x18] = (_height>>16)&0xFF;
      header[0x19] = (_height>>24)&0xFF;
      header[0x1A] = 1;
      header[0x1B] = 0;
      header[0x1C] = 24;
      header[0x1D] = 0;
      header[0x22] = buf_size&0xFF;
      header[0x23] = (buf_size>>8)&0xFF;
      header[0x24] = (buf_size>>16)&0xFF;
      header[0x25] = (buf_size>>24)&0xFF;
      header[0x27] = 0x1;
      header[0x2B] = 0x1;
      cimg::fwrite(header._data,54,nfile);

      const T
        *ptr_r = data(0,_height - 1,0,0),
        *ptr_g = (_spectrum>=2)?data(0,_height - 1,0,1):0,
        *ptr_b = (_spectrum>=3)?data(0,_height - 1,0,2):0;

      switch (_spectrum) {
      case 1 : {
        cimg_forY(*this,y) {
          cimg_forX(*this,x) {
            const unsigned char val = (unsigned char)*(ptr_r++);
            std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile);
          }
          cimg::fwrite(align_buf,align,nfile);
          ptr_r-=2*_width;
        }
      } break;
      case 2 : {
        cimg_forY(*this,y) {
          cimg_forX(*this,x) {
            std::fputc(0,nfile);
            std::fputc((unsigned char)(*(ptr_g++)),nfile);
            std::fputc((unsigned char)(*(ptr_r++)),nfile);
          }
          cimg::fwrite(align_buf,align,nfile);
          ptr_r-=2*_width; ptr_g-=2*_width;
        }
      } break;
      default : {
        cimg_forY(*this,y) {
          cimg_forX(*this,x) {
            std::fputc((unsigned char)(*(ptr_b++)),nfile);
            std::fputc((unsigned char)(*(ptr_g++)),nfile);
            std::fputc((unsigned char)(*(ptr_r++)),nfile);
          }
          cimg::fwrite(align_buf,align,nfile);
          ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width;
        }
      }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

      static unsigned int min() { return 0; }

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 11;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
      }
      ptre+=11;
      switch (ptre - ptrd) {
      case 11 : *(--ptre) = val10; // fallthrough
      case 10 : *(--ptre) = val9; // fallthrough
      case 9 : *(--ptre) = val8; // fallthrough
      case 8 : *(--ptre) = val7; // fallthrough
      case 7 : *(--ptre) = val6; // fallthrough
      case 6 : *(--ptre) = val5; // fallthrough
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename tf>
    static CImg<floatT> plane3d(CImgList<tf>& primitives,
                                const float size_x=100, const float size_y=100,
                                const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10) {
      primitives.assign();
      if (!subdivisions_x || !subdivisions_y) return CImg<floatT>();
      CImgList<floatT> vertices;
      const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1;
      const float fx = (float)size_x/w, fy = (float)size_y/h;
      for (unsigned int y = 0; y<h; ++y) for (unsigned int x = 0; x<w; ++x)
        CImg<floatT>::vector(fx*x,fy*y,0).move_to(vertices);
      for (unsigned int y = 0; y<subdivisions_y; ++y) for (unsigned int x = 0; x<subdivisions_x; ++x) {
        const int off1 = x + y*w, off2 = x + 1 + y*w, off3 = x + 1 + (y + 1)*w, off4 = x + (y + 1)*w;
	CImg<tf>::vector(off1,off4,off3,off2).move_to(primitives);
      }
      return vertices>'x';

Project: CImg
File: CImg.h

      static bool is_float() { return true; }
      static bool is_inf(const long double val) {
#ifdef isinf
        return (bool)isinf(val);
#else
        return !is_nan(val) && (val<cimg::type<half>::min() || val>cimg::type<half>::max());
#endif

Project: CImg
File: CImg.h

    template<typename T>
    inline T pow4(const T& val) {
      return val*val*val*val;

Project: CImg
File: CImg.h


      static double mp_isdir(_cimg_math_parser& mp) {
        const double *ptrs = &_mp_arg(2) + 1;
        const ulongT siz = (ulongT)mp.opcode[3];
        CImg<charT> ss(siz + 1);
        cimg_forX(ss,i) ss[i] = (char)ptrs[i];
        ss.back() = 0;
        return (double)cimg::is_directory(ss);

Project: CImg
File: CImg.h

        return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
      if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum);
      unsigned int siz[4] = { 0,1,1,1 }, k = 0;
      CImg<charT> item(256);
      for (const char *s = dimensions; *s && k<4; ++k) {
        if (cimg_sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item._data)>0) s+=std::strlen(item);
        if (*s) {
          unsigned int val = 0; char sep = 0;
          if (cimg_sscanf(s,"%u%c",&val,&sep)>0) {
            if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100;
            else siz[k] = val;
            while (*s>='0' && *s<='9') ++s;
            if (sep=='%') ++s;
          } else switch (cimg::lowercase(*s)) {
          case 'x' : case 'w' : siz[k] = img._width; ++s; break;
          case 'y' : case 'h' : siz[k] = img._height; ++s; break;
          case 'z' : case 'd' : siz[k] = img._depth; ++s; break;
          case 'c' : case 's' : siz[k] = img._spectrum; ++s; break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "assign(): Invalid character '%c' detected in specified dimension string '%s'.",
                                        cimg_instance,
                                        *s,dimensions);
          }
        }
      }
      return assign(siz[0],siz[1],siz[2],siz[3]);

Project: CImg
File: CImg.h

    **/
    CImg<Tfloat> operator/(const char *const expression) const {
      return CImg<Tfloat>(*this,false)/=expression;

Project: CImg
File: CImg.h

    **/
    CImg<T>& load_ascii(const char *const filename) {
      return _load_ascii(0,filename);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_bmp(const char *const filename) const {
      return _save_bmp(0,filename);

Project: CImg
File: CImg.h

    template<typename tf, typename tc>
    const CImg<T>& save_off(const CImgList<tf>& primitives, const CImgList<tc>& colors,
                            const char *const filename) const {
      return _save_off(primitives,colors,0,filename);

Project: CImg
File: CImg.h

    template<typename t>
    bool is_sameXYZ(const CImg<t>& img) const {
      return is_sameXYZ(img._width,img._height,img._depth);

Project: CImg
File: CImg.h

      static bool is_nan(const unsigned char) { return false; }

Project: CImg
File: CImg.h


    inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
      int one = 1;
      sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);

Project: CImg
File: CImg.h

    template<typename t>
    bool contains(const T& pixel, t& x) const {
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false;
      x = (t)(((ulongT)(ppixel - _data))%_width);
      return true;

Project: CImg
File: CImg.h

    **/
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
      CImg<T> r(1,4); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      return r;

Project: CImg
File: CImg.h

    template<typename T1, typename T2, typename T3, typename T4, typename T5>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);

Project: CImg
File: CImg.h


      static double mp_mul2(_cimg_math_parser& mp) {
        return _mp_arg(2)*_mp_arg(3)*_mp_arg(4);

Project: CImg
File: CImg.h

    //! Pointwise max operator between instance image and a value \newinstance.
    CImg<T> get_max(const T& value) const {
      return (+*this).max(value);

Project: CImg
File: CImg.h

    **/
    bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const {
      return is_sameYZ(size_y,size_z) && _spectrum==size_c;

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_rectangle(const int x0, const int y0,
                            const int x1, const int y1,
                            const tc *const color, const float opacity=1) {
      return draw_rectangle(x0,y0,0,x1,y1,_depth - 1,color,opacity);

Project: CImg
File: CImg.h


    CImgDisplay& paint() {
      if (_is_closed) return *this;
      WaitForSingleObject(_mutex,INFINITE);
      SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS);
      ReleaseMutex(_mutex);
      return *this;

Project: CImg
File: CImg.h

    **/
    const char *title() const {
      return _title?_title:"";

Project: CImg
File: CImg.h

    template<typename t>
    CImgList<T> get_split(const CImg<t>& values, const char axis=0, const bool keep_values=true) const {
      typedef _cimg_Tt Tt;

      CImgList<T> res;
      if (is_empty()) return res;
      const ulongT vsiz = values.size();
      const char _axis = cimg::lowercase(axis);
      if (!vsiz) return CImgList<T>(*this);
      if (vsiz==1) { // Split according to a single value
        const T value = (T)*values;
        switch (_axis) {
        case 'x' : {
          unsigned int i0 = 0, i = 0;
          do {
            while (i<_width && (*this)(i)==value) ++i;
            if (i>i0) { if (keep_values) get_columns(i0,i - 1).move_to(res); i0 = i; }
            while (i<_width && (*this)(i)!=value) ++i;
            if (i>i0) { get_columns(i0,i - 1).move_to(res); i0 = i; }
          } while (i<_width);
        } break;
        case 'y' : {
          unsigned int i0 = 0, i = 0;
          do {
            while (i<_height && (*this)(0,i)==value) ++i;
            if (i>i0) { if (keep_values) get_rows(i0,i - 1).move_to(res); i0 = i; }
            while (i<_height && (*this)(0,i)!=value) ++i;
            if (i>i0) { get_rows(i0,i - 1).move_to(res); i0 = i; }
          } while (i<_height);
        } break;
        case 'z' : {
          unsigned int i0 = 0, i = 0;
          do {
            while (i<_depth && (*this)(0,0,i)==value) ++i;
            if (i>i0) { if (keep_values) get_slices(i0,i - 1).move_to(res); i0 = i; }
            while (i<_depth && (*this)(0,0,i)!=value) ++i;
            if (i>i0) { get_slices(i0,i - 1).move_to(res); i0 = i; }
          } while (i<_depth);
        } break;
        case 'c' : {
          unsigned int i0 = 0, i = 0;
          do {
            while (i<_spectrum && (*this)(0,0,0,i)==value) ++i;
            if (i>i0) { if (keep_values) get_channels(i0,i - 1).move_to(res); i0 = i; }
            while (i<_spectrum && (*this)(0,0,0,i)!=value) ++i;
            if (i>i0) { get_channels(i0,i - 1).move_to(res); i0 = i; }
          } while (i<_spectrum);
        } break;
        default : {
          const ulongT siz = size();
          ulongT i0 = 0, i = 0;
          do {
            while (i<siz && (*this)[i]==value) ++i;
            if (i>i0) { if (keep_values) CImg<T>(_data + i0,1,(unsigned int)(i - i0)).move_to(res); i0 = i; }
            while (i<siz && (*this)[i]!=value) ++i;
            if (i>i0) { CImg<T>(_data + i0,1,(unsigned int)(i - i0)).move_to(res); i0 = i; }
          } while (i<siz);
        }
        }
      } else { // Split according to multiple values
        ulongT j = 0;
        switch (_axis) {
        case 'x' : {
          unsigned int i0 = 0, i1 = 0, i = 0;
          do {
            if ((Tt)(*this)(i)==(Tt)*values) {
              i1 = i; j = 0;
              while (i<_width && (Tt)(*this)(i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; }
              i-=j;
              if (i>i1) {
                if (i1>i0) get_columns(i0,i1 - 1).move_to(res);
                if (keep_values) get_columns(i1,i - 1).move_to(res);
                i0 = i;
              } else ++i;
            } else ++i;
          } while (i<_width);
          if (i0<_width) get_columns(i0,width() - 1).move_to(res);
        } break;
        case 'y' : {
          unsigned int i0 = 0, i1 = 0, i = 0;
          do {
            if ((Tt)(*this)(0,i)==(Tt)*values) {
              i1 = i; j = 0;
              while (i<_height && (Tt)(*this)(0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; }
              i-=j;
              if (i>i1) {
                if (i1>i0) get_rows(i0,i1 - 1).move_to(res);
                if (keep_values) get_rows(i1,i - 1).move_to(res);
                i0 = i;
              } else ++i;
            } else ++i;
          } while (i<_height);
          if (i0<_height) get_rows(i0,height() - 1).move_to(res);
        } break;
        case 'z' : {
          unsigned int i0 = 0, i1 = 0, i = 0;
          do {
            if ((Tt)(*this)(0,0,i)==(Tt)*values) {
              i1 = i; j = 0;
              while (i<_depth && (Tt)(*this)(0,0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; }
              i-=j;
              if (i>i1) {
                if (i1>i0) get_slices(i0,i1 - 1).move_to(res);
                if (keep_values) get_slices(i1,i - 1).move_to(res);
                i0 = i;
              } else ++i;
            } else ++i;
          } while (i<_depth);
          if (i0<_depth) get_slices(i0,depth() - 1).move_to(res);
        } break;
        case 'c' : {
          unsigned int i0 = 0, i1 = 0, i = 0;
          do {
            if ((Tt)(*this)(0,0,0,i)==(Tt)*values) {
              i1 = i; j = 0;
              while (i<_spectrum && (Tt)(*this)(0,0,0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; }
              i-=j;
              if (i>i1) {
                if (i1>i0) get_channels(i0,i1 - 1).move_to(res);
                if (keep_values) get_channels(i1,i - 1).move_to(res);
                i0 = i;
              } else ++i;
            } else ++i;
          } while (i<_spectrum);
          if (i0<_spectrum) get_channels(i0,spectrum() - 1).move_to(res);
        } break;
        default : {
          ulongT i0 = 0, i1 = 0, i = 0;
          const ulongT siz = size();
          do {
            if ((Tt)(*this)[i]==(Tt)*values) {
              i1 = i; j = 0;
              while (i<siz && (Tt)(*this)[i]==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; }
              i-=j;
              if (i>i1) {
                if (i1>i0) CImg<T>(_data + i0,1,(unsigned int)(i1 - i0)).move_to(res);
                if (keep_values) CImg<T>(_data + i1,1,(unsigned int)(i - i1)).move_to(res);
                i0 = i;
              } else ++i;
            } else ++i;
          } while (i<siz);
          if (i0<siz) CImg<T>(_data + i0,1,(unsigned int)(siz - i0)).move_to(res);
        } break;
        }
      }
      return res;

Project: CImg
File: CImg.h

    //! Convert pixel values from CMY to CMYK color spaces \newinstance.
    CImg<Tuchar> get_CMYtoCMYK() const {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "CMYtoCMYK(): Instance is not a CMY image.",
                                    cimg_instance);

      CImg<Tfloat> res(_width,_height,_depth,4);
      const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2);
      Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3);
      const longT whd = (longT)width()*height()*depth();
      cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,1024))
      for (longT N = 0; N<whd; ++N) {
        Tfloat
	  C = (Tfloat)ps1[N],
	  M = (Tfloat)ps2[N],
	  Y = (Tfloat)ps3[N],
	  K = cimg::min(C,M,Y);
	if (K>=255) C = M = Y = 0;
	else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; }
        pd1[N] = (Tfloat)cimg::cut(C,0,255),
        pd2[N] = (Tfloat)cimg::cut(M,0,255),
        pd3[N] = (Tfloat)cimg::cut(Y,0,255),
        pd4[N] = (Tfloat)cimg::cut(K,0,255);
      }
      return res;

Project: CImg
File: CImg.h

    template<typename T>
    inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
      dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);

Project: CImg
File: CImg.h

    //! Convert C-string to lower case.
    inline void lowercase(char *const str) {
      if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = lowercase(*ptr);

Project: CImg
File: CImg.h

    **/
    Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const {
      const int
	x = (int)fx - (fx>=0?0:1), nx = x + 1;
      const float
        dx = fx - x;
      const Tfloat
        Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value);
      return Ic + dx*(In - Ic);

Project: CImg
File: CImg.h

    template<typename tp, typename tf>
    const CImg<T>& display_object3d(const char *const title,
				    const CImg<tp>& vertices,
                                    const CImgList<tf>& primitives,
                                    const bool centering=true,
                                    const int render_static=4, const int render_motion=1,
                                    const bool is_double_sided=true, const float focale=700,
                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,
                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                                    const bool display_axes=true, float *const pose_matrix=0,
                                    const bool exit_on_anykey=false) const {
      return display_object3d(title,vertices,primitives,CImgList<T>(),centering,
                              render_static,render_motion,is_double_sided,focale,
                              light_x,light_y,light_z,specular_lightness,specular_shininess,
                              display_axes,pose_matrix,exit_on_anykey);

Project: CImg
File: CImg.h

    **/
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
			  const T& a3, const T& a4, const T& a5,
			  const T& a6, const T& a7, const T& a8) {
      CImg<T> r(3,3); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
      *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
      *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
      return r;

Project: CImg
File: CImg.h


    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) {
      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height];

Project: CImg
File: CImg.h

    //! Load gif file, using ImageMagick or GraphicsMagick's external tool 'convert' \newinstance.
    static CImg<T> get_load_gif_external(const char *const filename,
                                         const char axis='z', const float align=0) {
      return CImgList<T>().load_gif_external(filename).get_append(axis,align);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& append(const CImg<t>& img, const char axis='x', const float align=0) {
      if (is_empty()) return assign(img,false);
      if (!img) return *this;
      return CImgList<T>(*this,true).insert(img).get_append(axis,align).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const CImg<t>& img):_is_shared(false) {
      const size_t siz = (size_t)img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum),
                                      img._width,img._height,img._depth,img._spectrum);
        }
        const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }

Project: CImg
File: CImg.h

    template<typename T>
    static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
      img.assign();
      Display *dpy = cimg::X11_attr().display;
      cimg_lock_display();
      if (!dpy) {
        dpy = XOpenDisplay(0);
        if (!dpy)
          throw CImgDisplayException("CImgDisplay::screenshot(): Failed to open X11 display.");
      }
      Window root = DefaultRootWindow(dpy);
      XWindowAttributes gwa;
      XGetWindowAttributes(dpy,root,&gwa);
      const int width = gwa.width, height = gwa.height;
      int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1;
      if (_x0>_x1) cimg::swap(_x0,_x1);
      if (_y0>_y1) cimg::swap(_y0,_y1);

      XImage *image = 0;
      if (_x1>=0 && _x0<width && _y1>=0 && _y0<height) {
        _x0 = std::max(_x0,0);
        _y0 = std::max(_y0,0);
        _x1 = std::min(_x1,width - 1);
        _y1 = std::min(_y1,height - 1);
        image = XGetImage(dpy,root,_x0,_y0,_x1 - _x0 + 1,_y1 - _y0 + 1,AllPlanes,ZPixmap);

        if (image) {
          const unsigned long
            red_mask = image->red_mask,
            green_mask = image->green_mask,
            blue_mask = image->blue_mask;
          img.assign(image->width,image->height,1,3);
          T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2);
          cimg_forXY(img,x,y) {
            const unsigned long pixel = XGetPixel(image,x,y);
            *(pR++) = (T)((pixel & red_mask)>>16);
            *(pG++) = (T)((pixel & green_mask)>>8);
            *(pB++) = (T)(pixel & blue_mask);
          }
          XDestroyImage(image);
        }
      }
      if (!cimg::X11_attr().display) XCloseDisplay(dpy);
      cimg_unlock_display();
      if (img.is_empty())
        throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot "
                                   "with coordinates (%d,%d)-(%d,%d).",
                                   x0,y0,x1,y1);

Project: CImg
File: CImg.h


    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const {
      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];

Project: CImg
File: CImg.h

    **/
    inline bool endianness() {
      const int x = 1;
      return ((unsigned char*)&x)[0]?false:true;

Project: CImg
File: CImg.h


      static double mp_sign(_cimg_math_parser& mp) {
        return cimg::sign(_mp_arg(2));

Project: CImg
File: CImg.h

    **/
    CImg<T>& select(CImgDisplay &disp,
		    const unsigned int feature_type=2, unsigned int *const XYZ=0,
                    const bool exit_on_anykey=false,
                    const bool is_deep_selection_default=false) {
      return get_select(disp,feature_type,XYZ,exit_on_anykey,is_deep_selection_default).move_to(*this);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator%=(const t value) {
      if (is_empty()) return *this;
      cimg_openmp_for(*this,cimg::mod(*ptr,(T)value),16384);
      return *this;

Project: CImg
File: CImg.h

    //! Load image from a .cimg[z] file \newinstance
    static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const float align=0) {
      return CImg<T>().load_cimg(filename,axis,align);

Project: CImg
File: CImg.h


    T _cubic_atXY_pc(const float fx, const float fy, const int z, const int c) const {
      return cimg::type<T>::cut(_cubic_atXY_p(fx,fy,z,c));

Project: CImg
File: CImg.h

      static const char* string() { static const char *const s = "unsigned int64"; return s; }

Project: CImg
File: CImg.h


    CImgDisplay& set_mouse(const int posx, const int posy) {
      if (is_empty() || _is_closed || posx<0 || posy<0) return *this;
      _update_window_pos();
      const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);
      if (res) { _mouse_x = posx; _mouse_y = posy; }
      return *this;

Project: CImg
File: CImg.h

    template<typename T>
    inline T abs(const T& a) {
      return a>=0?a:-a;

Project: CImg
File: CImg.h

    //! Save image as a BMP file \overloading.
    const CImg<T>& save_bmp(std::FILE *const file) const {
      return _save_bmp(file,0);

Project: CImg
File: CImg.h

    **/
    CImg<T>& blur_box(const float boxsize, const bool boundary_conditions=true) {
      const float nboxsize = boxsize>=0?boxsize:-boxsize*cimg::max(_width,_height,_depth)/100;
      return blur_box(nboxsize,nboxsize,nboxsize,boundary_conditions);

Project: CImg
File: CImg.h

    //! Fill sequentially all pixel values with specified values \overloading.
    CImg<T>& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5,
                  const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11,
                  const T& val12, const T& val13) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end() - 13;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12; *(ptrd++) = val13;
      }
      ptre+=13;
      switch (ptre - ptrd) {
      case 13 : *(--ptre) = val12; // fallthrough
      case 12 : *(--ptre) = val11; // fallthrough
      case 11 : *(--ptre) = val10; // fallthrough
      case 10 : *(--ptre) = val9; // fallthrough
      case 9 : *(--ptre) = val8; // fallthrough
      case 8 : *(--ptre) = val7; // fallthrough
      case 7 : *(--ptre) = val6; // fallthrough
      case 6 : *(--ptre) = val5; // fallthrough
      case 5 : *(--ptre) = val4; // fallthrough
      case 4 : *(--ptre) = val3; // fallthrough
      case 3 : *(--ptre) = val2; // fallthrough
      case 2 : *(--ptre) = val1; // fallthrough
      case 1 : *(--ptre) = val0; // fallthrough
      }
      return *this;

Project: CImg
File: CImg.h

      static bool min() { return false; }

Project: CImg
File: CImg.h

    //! Compute the bitwise right rotation of each pixel value \newinstance.
    CImg<T> get_ror(const char *const expression) const {
      return (+*this).ror(expression);

Project: CImg
File: CImg.h

    //! Simple interface to select a shape from an image \newinstance.
    CImg<intT> get_select(CImgDisplay &disp,
		          const unsigned int feature_type=2, unsigned int *const XYZ=0,
                          const bool exit_on_anykey=false,
                          const bool is_deep_selection_default=false) const {
      return _select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false,is_deep_selection_default);

Project: CImg
File: CImg.h


      static double mp_self_div(_cimg_math_parser& mp) {
        return _mp_arg(1)/=_mp_arg(2);

Project: CImg
File: CImg.h

     **/
    CImg<T>& operator*=(const char *const expression) {
      return mul((+*this)._fill(expression,true,1,0,0,"operator*=",this));

Project: CImg
File: CImg.h

    template<typename T>
    CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "render(): Empty specified image.",
                                    cimgdisplay_instance);
      if (is_empty()) return *this;
      if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2,
                                                             (img._depth - 1)/2));
      if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height))
        return render(img.get_resize(_width,_height,1,-100,1));
      if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) {
        static const CImg<typename CImg<T>::ucharT> default_colormap = CImg<typename CImg<T>::ucharT>::default_LUT256();
        return render(img.get_index(default_colormap,1,false));
      }

      const T
        *data1 = img._data,
        *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1,
        *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1;

      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
      cimg_lock_display();

      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
        _min = _max = 0;
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 colormap, no normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char
            *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
            new unsigned char[(size_t)img._width*img._height],
            *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 :
            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
              (*ptrd++) = (unsigned char)*(data1++);
            break;
          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
	      const unsigned char
                R = (unsigned char)*(data1++),
                G = (unsigned char)*(data2++);
	      (*ptrd++) = (R&0xf0) | (G>>4);
	    } break;
          default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
	      const unsigned char
                R = (unsigned char)*(data1++),
                G = (unsigned char)*(data2++),
                B = (unsigned char)*(data3++);
	      (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
	    }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        case 16 : { // 16 bits colors, no normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
            new unsigned short[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)*(data1++), G = val>>2;
                ptrd[0] = (val&M) | (G>>3);
                ptrd[1] = (G<<5) | (G>>1);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)*(data1++), G = val>>2;
                ptrd[0] = (G<<5) | (G>>1);
                ptrd[1] = (val&M) | (G>>3);
                ptrd+=2;
              }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd[1] = (G<<5);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = (G<<5);
                ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd+=2;
              }
            break;
          default :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd[1] = (G<<5) | ((unsigned char)*(data3++)>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)*(data2++)>>2;
                ptrd[0] = (G<<5) | ((unsigned char)*(data3++)>>3);
                ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3);
                ptrd+=2;
              }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        default : { // 24 bits colors, no normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
            new unsigned int[(size_t)img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                 const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) |
                    (unsigned char)*(data3++);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) |
                    ((unsigned char)*(data1++)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)*(data1++);
                  ptrd[2] = 0;
                  ptrd[3] = 0;
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = 0;
                  ptrd[2] = (unsigned char)*(data1++);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                ptrd[0] = 0;
                ptrd[1] = (unsigned char)*(data2++);
                ptrd[2] = (unsigned char)*(data1++);
                ptrd[3] = 0;
                ptrd+=4;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)*(data1++);
                  ptrd[2] = (unsigned char)*(data2++);
                  ptrd[3] = (unsigned char)*(data3++);
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = (unsigned char)*(data3++);
                  ptrd[1] = (unsigned char)*(data2++);
                  ptrd[2] = (unsigned char)*(data1++);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
            delete[] ndata;
          }
        }
        }
      } else {
        if (_normalization==3) {
          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
        const float delta = _max - _min, mm = 255/(delta?delta:1.f);
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 colormap, with normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:
            new unsigned char[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char R = (unsigned char)((*(data1++) - _min)*mm);
              *(ptrd++) = R;
            } break;
          case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++) - _min)*mm),
                G = (unsigned char)((*(data2++) - _min)*mm);
            (*ptrd++) = (R&0xf0) | (G>>4);
          } break;
          default :
            for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++) - _min)*mm),
                G = (unsigned char)((*(data2++) - _min)*mm),
                B = (unsigned char)((*(data3++) - _min)*mm);
              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        case 16 : { // 16 bits colors, with normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:
            new unsigned short[(size_t)img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
                ptrd[0] = (val&M) | (G>>3);
                ptrd[1] = (G<<5) | (val>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2;
                ptrd[0] = (G<<5) | (val>>3);
                ptrd[1] = (val&M) | (G>>3);
                ptrd+=2;
              }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd[1] = (G<<5);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = (G<<5);
                ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd+=2;
              }
            break;
          default :
            if (cimg::X11_attr().byte_order)
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd[1] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
                ptrd+=2;
              } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2;
                ptrd[0] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3);
                ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3);
                ptrd+=2;
              }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height);
            delete[] ndata;
          }
        } break;
        default : { // 24 bits colors, with normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:
            new unsigned int[(size_t)img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<8);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data1++) - _min)*mm)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<8) |
                    (unsigned char)((*(data3++) - _min)*mm);
              else
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data3++) - _min)*mm)<<24) |
                    ((unsigned char)((*(data2++) - _min)*mm)<<16) |
                    ((unsigned char)((*(data1++) - _min)*mm)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[0] = 0;
                  ptrd[1] = val;
                  ptrd[2] = val;
                  ptrd[3] = val;
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[0] = val;
                  ptrd[1] = val;
                  ptrd[2] = val;
                  ptrd[3] = 0;
                  ptrd+=4;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                ptrd[0] = 0;
                ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
                ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
                ptrd[3] = 0;
                ptrd+=4;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order)
                for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = 0;
                  ptrd[1] = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[2] = (unsigned char)((*(data2++) - _min)*mm);
                  ptrd[3] = (unsigned char)((*(data3++) - _min)*mm);
                  ptrd+=4;
                } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) {
                  ptrd[0] = (unsigned char)((*(data3++) - _min)*mm);
                  ptrd[1] = (unsigned char)((*(data2++) - _min)*mm);
                  ptrd[2] = (unsigned char)((*(data1++) - _min)*mm);
                  ptrd[3] = 0;
                  ptrd+=4;
                }
            }
          }
          if (ndata!=_data) {
            _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height);
            delete[] ndata;
          }
	}
        }
      }
      cimg_unlock_display();
      return *this;

Project: CImg
File: CImg.h

    template<typename tf, typename tc>
    const CImg<T>& _save_off(const CImgList<tf>& primitives, const CImgList<tc>& colors,
                             std::FILE *const file, const char *const filename) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_off(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "save_off(): Empty instance, for file '%s'.",
                                    cimg_instance,
                                    filename?filename:"(FILE*)");

      CImgList<T> opacities;
      CImg<charT> error_message(1024);
      if (!is_object3d(primitives,colors,opacities,true,error_message))
        throw CImgInstanceException(_cimg_instance
                                    "save_off(): Invalid specified 3D object, for file '%s' (%s).",
                                    cimg_instance,
                                    filename?filename:"(FILE*)",error_message.data());

      const CImg<tc> default_color(1,3,1,1,(tc)std::min((int)cimg::type<tc>::max(),200));
      std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
      unsigned int supported_primitives = 0;
      cimglist_for(primitives,l) if (primitives[l].size()!=5) ++supported_primitives;
      std::fprintf(nfile,"OFF\n%u %u %u\n",_width,supported_primitives,3*primitives._width);
      cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n",
                                      (float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
      cimglist_for(primitives,l) {
        const CImg<tc>& color = l<colors.width()?colors[l]:default_color;
        const unsigned int psiz = primitives[l].size(), csiz = color.size();
        const float r = color[0]/255.f, g = (csiz>1?color[1]:r)/255.f, b = (csiz>2?color[2]:g)/255.f;
        switch (psiz) {
        case 1 : std::fprintf(nfile,"1 %u %f %f %f\n",
                              (unsigned int)primitives(l,0),r,g,b); break;
        case 2 : std::fprintf(nfile,"2 %u %u %f %f %f\n",
                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break;
        case 3 : std::fprintf(nfile,"3 %u %u %u %f %f %f\n",
                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
                              (unsigned int)primitives(l,1),r,g,b); break;
        case 4 : std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
                              (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break;
        case 5 : std::fprintf(nfile,"2 %u %u %f %f %f\n",
                              (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break;
        case 6 : {
          const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3);
          const float
            rt = color.atXY(xt,yt,0)/255.f,
            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f,
            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f;
          std::fprintf(nfile,"2 %u %u %f %f %f\n",
                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),rt,gt,bt);
        } break;
        case 9 : {
          const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4);
          const float
            rt = color.atXY(xt,yt,0)/255.f,
            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f,
            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f;
          std::fprintf(nfile,"3 %u %u %u %f %f %f\n",
                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
                       (unsigned int)primitives(l,1),rt,gt,bt);
        } break;
        case 12 : {
          const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5);
          const float
            rt = color.atXY(xt,yt,0)/255.f,
            gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f,
            bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f;
          std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
                       (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),
                       (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),rt,gt,bt);
        } break;
        }
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


    inline bool option(const char *const name, const int argc, const char *const *const argv,
                       const bool defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
      cimg::option(name,0,0,res?"true":"false",usage);
      return res;

Project: CImg
File: CImg.h

      return filename_local;
    }

    // Implement a tic/toc mechanism to display elapsed time of algorithms.
    inline cimg_ulong tictoc(const bool is_tic) {
      cimg::mutex(2);
      static CImg<cimg_ulong> times(64);
      static unsigned int pos = 0;
      const cimg_ulong t1 = cimg::time();
      if (is_tic) {
        // Tic
        times[pos++] = t1;
        if (pos>=times._width)
          throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'.");
        cimg::mutex(2,0);
        return t1;
      }

      // Toc
      if (!pos)
        throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made.");
      const cimg_ulong
        t0 = times[--pos],
        dt = t1>=t0?(t1 - t0):cimg::type<cimg_ulong>::max();
      const unsigned int
        edays = (unsigned int)(dt/86400000.),
        ehours = (unsigned int)((dt - edays*86400000.)/3600000.),
        emin = (unsigned int)((dt - edays*86400000. - ehours*3600000.)/60000.),
        esec = (unsigned int)((dt - edays*86400000. - ehours*3600000. - emin*60000.)/1000.),
        ems = (unsigned int)(dt - edays*86400000. - ehours*3600000. - emin*60000. - esec*1000.);
      if (!edays && !ehours && !emin && !esec)
        std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n",
                     cimg::t_red,1 + 2*pos,"",ems,cimg::t_normal);
      else {
        if (!edays && !ehours && !emin)
          std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n",
                       cimg::t_red,1 + 2*pos,"",esec,ems,cimg::t_normal);
        else {
          if (!edays && !ehours)
            std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n",
                         cimg::t_red,1 + 2*pos,"",emin,esec,ems,cimg::t_normal);
          else{
            if (!edays)
              std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n",
                           cimg::t_red,1 + 2*pos,"",ehours,emin,esec,ems,cimg::t_normal);
            else{
              std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n",
                           cimg::t_red,1 + 2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal);
            }
          }
        }

Project: CImg
File: CImg.h


    CImgDisplay& assign(const CImgDisplay& disp) {
      if (!disp) return assign();
      _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);
      std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height);
      return paint();

Project: CImg
File: CImg.h

    **/
    CImg<T>& operator=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode(0);
      try {
        _fill(expression,true,1,0,0,"operator=",0);
      } catch (CImgException&) {
        cimg::exception_mode(omode);
        load(expression);
      }
      cimg::exception_mode(omode);
      return *this;

Project: CImg
File: CImg.h


    CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) {
#define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
        cimg::fread(dims,nbdim,nfile); \
        if (endian) cimg::invert_endianness(dims,nbdim); \
        assign(nwidth,nheight,ndepth,ndim); \
        const size_t siz = size(); \
        stype *buffer = new stype[siz]; \
        cimg::fread(buffer,siz,nfile); \
        if (endian) cimg::invert_endianness(buffer,siz); \
        T *ptrd = _data; \
        cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
        buffer-=siz; \
        delete[] buffer

#define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
        if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
        else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
        else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
        else throw CImgIOException(_cimg_instance \
                                   "load_pandore(): Unknown pixel datatype in file '%s'.", \
                                   cimg_instance, \
                                   filename?filename:"(FILE*)"); }
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_pandore(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      CImg<charT> header(32);
      cimg::fread(header._data,12,nfile);
      if (cimg::strncasecmp("PANDORE",header,7)) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pandore(): PANDORE header not found in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      unsigned int imageid, dims[8] = { 0 };
      int ptbuf[4] = { 0 };
      cimg::fread(&imageid,1,nfile);
      const bool endian = imageid>255;
      if (endian) cimg::invert_endianness(imageid);
      cimg::fread(header._data,20,nfile);

      switch (imageid) {
      case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break;
      case 3 : _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
      case 4 : _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
      case 5 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break;
      case 6 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
      case 7 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
      case 8 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break;
      case 9 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
      case 10 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
      case 11 : { // Region 1D
        cimg::fread(dims,3,nfile);
        if (endian) cimg::invert_endianness(dims,3);
        assign(dims[1],1,1,1);
        const unsigned siz = size();
        if (dims[2]<256) {
          unsigned char *buffer = new unsigned char[siz];
          cimg::fread(buffer,siz,nfile);
          T *ptrd = _data;
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
          buffer-=siz;
          delete[] buffer;
        } else {
          if (dims[2]<65536) {
            unsigned short *buffer = new unsigned short[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          } else {
            unsigned int *buffer = new unsigned int[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          }
        }
      }
        break;
      case 12 : { // Region 2D
        cimg::fread(dims,4,nfile);
        if (endian) cimg::invert_endianness(dims,4);
        assign(dims[2],dims[1],1,1);
        const size_t siz = size();
        if (dims[3]<256) {
          unsigned char *buffer = new unsigned char[siz];
          cimg::fread(buffer,siz,nfile);
          T *ptrd = _data;
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
          buffer-=siz;
          delete[] buffer;
        } else {
          if (dims[3]<65536) {
            unsigned short *buffer = new unsigned short[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          } else {
            unsigned int *buffer = new unsigned int[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          }
        }
      }
        break;
      case 13 : { // Region 3D
        cimg::fread(dims,5,nfile);
        if (endian) cimg::invert_endianness(dims,5);
        assign(dims[3],dims[2],dims[1],1);
        const size_t siz = size();
        if (dims[4]<256) {
          unsigned char *buffer = new unsigned char[siz];
          cimg::fread(buffer,siz,nfile);
          T *ptrd = _data;
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
          buffer-=siz;
          delete[] buffer;
        } else {
          if (dims[4]<65536) {
            unsigned short *buffer = new unsigned short[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          } else {
            unsigned int *buffer = new unsigned int[siz];
            cimg::fread(buffer,siz,nfile);
            if (endian) cimg::invert_endianness(buffer,siz);
            T *ptrd = _data;
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
            buffer-=siz;
            delete[] buffer;
          }
        }
      }
        break;
      case 16 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break;
      case 17 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
      case 18 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
      case 19 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break;
      case 20 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
      case 21 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
      case 22 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break;
      case 23 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); break;
      case 24 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break;
      case 25 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
      case 26 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break;
      case 27 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
      case 28 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break;
      case 29 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
      case 30 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1);
        break;
      case 31 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
      case 32 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4);
        break;
      case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
      case 34 : { // Points 1D
        cimg::fread(ptbuf,1,nfile);
        if (endian) cimg::invert_endianness(ptbuf,1);
        assign(1); (*this)(0) = (T)ptbuf[0];
      } break;
      case 35 : { // Points 2D
        cimg::fread(ptbuf,2,nfile);
        if (endian) cimg::invert_endianness(ptbuf,2);
        assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
      } break;
      case 36 : { // Points 3D
        cimg::fread(ptbuf,3,nfile);
        if (endian) cimg::invert_endianness(ptbuf,3);
        assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
      } break;
      default :
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pandore(): Unable to load data with ID_type %u in file '%s'.",
                              cimg_instance,
                              imageid,filename?filename:"(FILE*)");
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h


    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) {
      return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth];

Project: CImg
File: CImg.h

    **/
    T cubic_atX_c(const float fx, const int y, const int z, const int c) const {
      return cimg::type<T>::cut(cubic_atX(fx,y,z,c));

Project: CImg
File: CImg.h

      static int min() { return ~max(); }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator^=(const t value) {
      if (is_empty()) return *this;
      cimg_openmp_for(*this,(ulongT)*ptr ^ (ulongT)value,32768);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImgDisplay& move(const int pos_x, const int pos_y) {
      return assign(pos_x,pos_y);

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Tt> operator/(const t value) const {
      return CImg<_cimg_Tt>(*this,false)/=value;

Project: CImg
File: CImg.h

    /**
       \param[out] max_val Value of the maximum value found.
    **/
    template<typename t>
    const T& min_max(t& max_val) const {
      bool is_all_empty = true;
      T *ptr_min = 0;
      cimglist_for(*this,l) if (!_data[l].is_empty()) {
        ptr_min = _data[l]._data;
        is_all_empty = false;
        break;
      }
      if (is_all_empty)
        throw CImgInstanceException(_cimglist_instance
                                    "min_max(): %s.",
                                    _data?"List of empty images":"Empty instance",
                                    cimglist_instance);
      T min_value = *ptr_min, max_value = min_value;
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        cimg_for(img,ptrs,T) {
          const T val = *ptrs;
          if (val<min_value) { min_value = val; ptr_min = ptrs; }
          if (val>max_value) max_value = val;
        }

Project: CImg
File: CImg.h


    Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = cimg::type<float>::is_nan(fx)?0:cimg::cut(fx,0,width() - 1);
      const int
        x = (int)nfx;
      const float
        dx = nfx - x;
      const int
        px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2;
      const Tfloat
        Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),
        In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);
      return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia));

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, typename to, typename tz>
    CImg<T>& draw_object3d(LibBoard::Board& board,
                           const float x0, const float y0, const float z0,
                           const CImg<tp>& vertices, const CImgList<tf>& primitives,
                           const CImgList<tc>& colors,
                           const unsigned int render_type,
                           const bool is_double_sided, const float focale,
                           const float lightx, const float lighty, const float lightz,
                           const float specular_lightness, const float specular_shininess,
                           const float g_opacity, CImg<tz>& zbuffer) {
      return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
                           render_type,is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,g_opacity,zbuffer);

Project: CImg
File: CImg.h

    //! Wait for any window event occuring in any opened CImgDisplay.
    static void wait_all() {
      return _no_display_exception();

Project: CImg
File: CImg.h

      return _load_cimg(file,0);
    }

Project: CImg
File: CImg.h

    //! Access to pixel value with Dirichlet boundary conditions for the 3 coordinates (\c pos, \c x,\c y) \const.
    T atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const {
      return (pos<0 || pos>=width())?out_value:_data[pos].atXY(x,y,z,c,out_value);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_cimg(const char *const filename,
                             const unsigned int n0,
                             const unsigned int x0, const unsigned int y0,
                             const unsigned int z0, const unsigned int c0) const {
      CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,c0);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& correlate(const CImg<t>& kernel, const bool boundary_conditions=true,
                       const bool is_normalized=false, const int dilation=1) {
      if (is_empty() || !kernel) return *this;
      return get_correlate(kernel,boundary_conditions,is_normalized,dilation).move_to(*this);

Project: CImg
File: CImg.h

    template<typename tz, typename tp, typename tf, typename tc, typename to>
    CImg<T>& _draw_object3d(void *const pboard, CImg<tz>& zbuffer,
                            const float X, const float Y, const float Z,
                            const CImg<tp>& vertices,
                            const CImgList<tf>& primitives,
                            const CImgList<tc>& colors,
                            const to& opacities,
                            const unsigned int render_type,
                            const bool is_double_sided, const float focale,
                            const float lightx, const float lighty, const float lightz,
                            const float specular_lightness, const float specular_shininess,
                            const float g_opacity, const float sprite_scale) {
      typedef typename cimg::superset2<tp,tz,float>::type tpfloat;
      typedef typename to::value_type _to;
      if (is_empty() || !vertices || !primitives) return *this;
      CImg<char> error_message(1024);
      if (!vertices.is_object3d(primitives,colors,opacities,false,error_message))
        throw CImgArgumentException(_cimg_instance
                                    "draw_object3d(): Invalid specified 3D object (%u,%u) (%s).",
                                    cimg_instance,vertices._width,primitives._width,error_message.data());
#ifndef cimg_use_board
      if (pboard) return *this;
#endif
      if (render_type==5) cimg::mutex(10); // Static variable used in this case, breaks thread-safety

      const float
        nspec = 1 - (specular_lightness<0.f?0.f:(specular_lightness>1.f?1.f:specular_lightness)),
        nspec2 = 1 + (specular_shininess<0.f?0.f:specular_shininess),
        nsl1 = (nspec2 - 1)/cimg::sqr(nspec - 1),
        nsl2 = 1 - 2*nsl1*nspec,
        nsl3 = nspec2 - nsl1 - nsl2;

      // Create light texture for phong-like rendering.
      CImg<floatT> light_texture;
      if (render_type==5) {
        if (colors._width>primitives._width) {
          static CImg<floatT> default_light_texture;
          static const tc *lptr = 0;
          static tc ref_values[64] = { 0 };
          const CImg<tc>& img = colors.back();
          bool is_same_texture = (lptr==img._data);
          if (is_same_texture)
            for (unsigned int r = 0, j = 0; j<8; ++j)
              for (unsigned int i = 0; i<8; ++i)
                if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum)) {
                  is_same_texture = false; break;
                }
          if (!is_same_texture || default_light_texture._spectrum<_spectrum) {
            (default_light_texture.assign(img,false)/=255).resize(-100,-100,1,_spectrum);
            lptr = colors.back().data();
            for (unsigned int r = 0, j = 0; j<8; ++j)
              for (unsigned int i = 0; i<8; ++i)
                ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum);
          }
          light_texture.assign(default_light_texture,true);
        } else {
          static CImg<floatT> default_light_texture;
          static float olightx = 0, olighty = 0, olightz = 0, ospecular_shininess = 0;
          if (!default_light_texture ||
              lightx!=olightx || lighty!=olighty || lightz!=olightz ||
              specular_shininess!=ospecular_shininess || default_light_texture._spectrum<_spectrum) {
            default_light_texture.assign(512,512);
            const float
              dlx = lightx - X,
              dly = lighty - Y,
              dlz = lightz - Z,
              nl = cimg::hypot(dlx,dly,dlz),
              nlx = (default_light_texture._width - 1)/2*(1 + dlx/nl),
              nly = (default_light_texture._height - 1)/2*(1 + dly/nl),
              white[] = { 1 };
            default_light_texture.draw_gaussian(nlx,nly,default_light_texture._width/3.f,white);
            cimg_forXY(default_light_texture,x,y) {
              const float factor = default_light_texture(x,y);
              if (factor>nspec) default_light_texture(x,y) = std::min(2.f,nsl1*factor*factor + nsl2*factor + nsl3);
            }
            default_light_texture.resize(-100,-100,1,_spectrum);
            olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shininess = specular_shininess;
          }
          light_texture.assign(default_light_texture,true);
        }
      }

      // Compute 3D to 2D projection.
      CImg<tpfloat> projections(vertices._width,2);
      tpfloat parallzmin = cimg::type<tpfloat>::max();
      const float absfocale = focale?cimg::abs(focale):0;
      if (absfocale) {
        cimg_pragma_openmp(parallel for cimg_openmp_if_size(projections.size(),4096))
        cimg_forX(projections,l) { // Perspective projection
          const tpfloat
            x = (tpfloat)vertices(l,0),
            y = (tpfloat)vertices(l,1),
            z = (tpfloat)vertices(l,2);
          const tpfloat projectedz = z + Z + absfocale;
          projections(l,1) = Y + absfocale*y/projectedz;
          projections(l,0) = X + absfocale*x/projectedz;
        }
      } else {
        cimg_pragma_openmp(parallel for cimg_openmp_if_size(projections.size(),4096))
        cimg_forX(projections,l) { // Parallel projection
          const tpfloat
            x = (tpfloat)vertices(l,0),
            y = (tpfloat)vertices(l,1),
            z = (tpfloat)vertices(l,2);
          if (z<parallzmin) parallzmin = z;
          projections(l,1) = Y + y;
          projections(l,0) = X + x;
        }
      }

      const float _focale = absfocale?absfocale:(1e5f-parallzmin);
      float zmax = 0;
      if (zbuffer) zmax = vertices.get_shared_row(2).max();

      // Compute visible primitives.
      CImg<uintT> visibles(primitives._width,1,1,1,~0U);
      CImg<tpfloat> zrange(primitives._width);
      const tpfloat zmin = absfocale?(tpfloat)(1.5f - absfocale):cimg::type<tpfloat>::min();
      bool is_forward = zbuffer?true:false;

      cimg_pragma_openmp(parallel for cimg_openmp_if_size(primitives.size(),4096))
      cimglist_for(primitives,l) {
        const CImg<tf>& primitive = primitives[l];
        switch (primitive.size()) {
        case 1 : { // Point
          CImg<_to> _opacity;
          __draw_object3d(opacities,l,_opacity);
          if (l<=colors.width() && (colors[l].size()!=_spectrum || _opacity)) is_forward = false;
          const unsigned int i0 = (unsigned int)primitive(0);
          const tpfloat z0 = Z + vertices(i0,2);
          if (z0>zmin) {
            visibles(l) = (unsigned int)l;
            zrange(l) = z0;
          }
        } break;
        case 5 : { // Sphere
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          const tpfloat
            Xc = 0.5f*((float)vertices(i0,0) + (float)vertices(i1,0)),
            Yc = 0.5f*((float)vertices(i0,1) + (float)vertices(i1,1)),
            Zc = 0.5f*((float)vertices(i0,2) + (float)vertices(i1,2)),
            _zc = Z + Zc,
            zc = _zc + _focale,
            xc = X + Xc*(absfocale?absfocale/zc:1),
            yc = Y + Yc*(absfocale?absfocale/zc:1),
            radius = 0.5f*cimg::hypot(vertices(i1,0) - vertices(i0,0),
                                      vertices(i1,1) - vertices(i0,1),
                                      vertices(i1,2) - vertices(i0,2))*(absfocale?absfocale/zc:1),
            xm = xc - radius,
            ym = yc - radius,
            xM = xc + radius,
            yM = yc + radius;
          if (xM>=0 && xm<_width && yM>=0 && ym<_height && _zc>zmin) {
            visibles(l) = (unsigned int)l;
            zrange(l) = _zc;
          }
          is_forward = false;
        } break;
        case 2 : case 6 : { // Segment
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          const tpfloat
            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),
            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2);
          tpfloat xm, xM, ym, yM;
          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin) {
            visibles(l) = (unsigned int)l;
            zrange(l) = (z0 + z1)/2;
          }
        } break;
        case 3 : case 9 : { // Triangle
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2);
          const tpfloat
            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),
            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2),
            x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2);
          tpfloat xm, xM, ym, yM;
          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
          if (x2<xm) xm = x2;
          if (x2>xM) xM = x2;
          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
          if (y2<ym) ym = y2;
          if (y2>yM) yM = y2;
          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) {
            const tpfloat d = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0);
            if (is_double_sided || d<0) {
              visibles(l) = (unsigned int)l;
              zrange(l) = (z0 + z1 + z2)/3;
            }
          }
        } break;
        case 4 : case 12 : { // Quadrangle
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2),
            i3 = (unsigned int)primitive(3);
          const tpfloat
            x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2),
            x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2),
            x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2),
            x3 = projections(i3,0), y3 = projections(i3,1), z3 = Z + vertices(i3,2);
          tpfloat xm, xM, ym, yM;
          if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
          if (x2<xm) xm = x2;
          if (x2>xM) xM = x2;
          if (x3<xm) xm = x3;
          if (x3>xM) xM = x3;
          if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
          if (y2<ym) ym = y2;
          if (y2>yM) yM = y2;
          if (y3<ym) ym = y3;
          if (y3>yM) yM = y3;
          if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin && z3>zmin) {
            const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
            if (is_double_sided || d<0) {
              visibles(l) = (unsigned int)l;
              zrange(l) = (z0 + z1 + z2 + z3)/4;
            }
          }
        } break;
        default :
          if (render_type==5) cimg::mutex(10,0);
          throw CImgArgumentException(_cimg_instance
                                      "draw_object3d(): Invalid primitive[%u] with size %u "
                                      "(should have size 1,2,3,4,5,6,9 or 12).",
                                      cimg_instance,
                                      l,primitive.size());
        }
      }

      // Force transparent primitives to be drawn last when zbuffer is activated
      // (and if object contains no spheres or sprites).
      if (is_forward)
        cimglist_for(primitives,l)
          if (___draw_object3d(opacities,l)!=1) zrange(l) = 2*zmax - zrange(l);

      // Sort only visibles primitives.
      unsigned int *p_visibles = visibles._data;
      tpfloat *p_zrange = zrange._data;
      const tpfloat *ptrz = p_zrange;
      cimg_for(visibles,ptr,unsigned int) {
        if (*ptr!=~0U) { *(p_visibles++) = *ptr; *(p_zrange++) = *ptrz; }
        ++ptrz;
      }
      const unsigned int nb_visibles = (unsigned int)(p_zrange - zrange._data);
      if (!nb_visibles) {
        if (render_type==5) cimg::mutex(10,0);
        return *this;
      }
      CImg<uintT> permutations;
      CImg<tpfloat>(zrange._data,nb_visibles,1,1,1,true).sort(permutations,is_forward);

      // Compute light properties
      CImg<floatT> lightprops;
      switch (render_type) {
      case 3 : { // Flat Shading
        lightprops.assign(nb_visibles);
        cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096))
        cimg_forX(lightprops,l) {
          const CImg<tf>& primitive = primitives(visibles(permutations(l)));
          const unsigned int psize = (unsigned int)primitive.size();
          if (psize==3 || psize==4 || psize==9 || psize==12) {
            const unsigned int
              i0 = (unsigned int)primitive(0),
              i1 = (unsigned int)primitive(1),
              i2 = (unsigned int)primitive(2);
            const tpfloat
              x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2),
              x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2),
              x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2),
              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
              nx = dy1*dz2 - dz1*dy2,
              ny = dz1*dx2 - dx1*dz2,
              nz = dx1*dy2 - dy1*dx2,
              norm = 1e-5f + cimg::hypot(nx,ny,nz),
              lx = X + (x0 + x1 + x2)/3 - lightx,
              ly = Y + (y0 + y1 + y2)/3 - lighty,
              lz = Z + (z0 + z1 + z2)/3 - lightz,
              nl = 1e-5f + cimg::hypot(lx,ly,lz),
              factor = std::max(cimg::abs(-lx*nx - ly*ny - lz*nz)/(norm*nl),(tpfloat)0);
            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
          } else lightprops[l] = 1;
        }
      } break;

      case 4 : // Gouraud Shading
      case 5 : { // Phong-Shading
        CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0);
        cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096))
        for (int l = 0; l<(int)nb_visibles; ++l) {
          const CImg<tf>& primitive = primitives[visibles(l)];
          const unsigned int psize = (unsigned int)primitive.size();
          const bool
            triangle_flag = (psize==3) || (psize==9),
            quadrangle_flag = (psize==4) || (psize==12);
          if (triangle_flag || quadrangle_flag) {
            const unsigned int
              i0 = (unsigned int)primitive(0),
              i1 = (unsigned int)primitive(1),
              i2 = (unsigned int)primitive(2),
              i3 = quadrangle_flag?(unsigned int)primitive(3):0;
            const tpfloat
              x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2),
              x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2),
              x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2),
              dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
              dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
              nnx = dy1*dz2 - dz1*dy2,
              nny = dz1*dx2 - dx1*dz2,
              nnz = dx1*dy2 - dy1*dx2,
              norm = 1e-5f + cimg::hypot(nnx,nny,nnz),
              nx = nnx/norm,
              ny = nny/norm,
              nz = nnz/norm;
            unsigned int ix = 0, iy = 1, iz = 2;
            if (is_double_sided && nz>0) { ix = 3; iy = 4; iz = 5; }
            vertices_normals(i0,ix)+=nx; vertices_normals(i0,iy)+=ny; vertices_normals(i0,iz)+=nz;
            vertices_normals(i1,ix)+=nx; vertices_normals(i1,iy)+=ny; vertices_normals(i1,iz)+=nz;
            vertices_normals(i2,ix)+=nx; vertices_normals(i2,iy)+=ny; vertices_normals(i2,iz)+=nz;
            if (quadrangle_flag) {
              vertices_normals(i3,ix)+=nx; vertices_normals(i3,iy)+=ny; vertices_normals(i3,iz)+=nz;
            }
          }
        }

        if (is_double_sided) cimg_forX(vertices_normals,p) {
            const float
              nx0 = vertices_normals(p,0), ny0 = vertices_normals(p,1), nz0 = vertices_normals(p,2),
              nx1 = vertices_normals(p,3), ny1 = vertices_normals(p,4), nz1 = vertices_normals(p,5),
              n0 = nx0*nx0 + ny0*ny0 + nz0*nz0, n1 = nx1*nx1 + ny1*ny1 + nz1*nz1;
            if (n1>n0) {
              vertices_normals(p,0) = -nx1;
              vertices_normals(p,1) = -ny1;
              vertices_normals(p,2) = -nz1;
            }
          }

        if (render_type==4) {
          lightprops.assign(vertices._width);
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096))
          cimg_forX(lightprops,l) {
            const tpfloat
              nx = vertices_normals(l,0),
              ny = vertices_normals(l,1),
              nz = vertices_normals(l,2),
              norm = 1e-5f + cimg::hypot(nx,ny,nz),
              lx = X + vertices(l,0) - lightx,
              ly = Y + vertices(l,1) - lighty,
              lz = Z + vertices(l,2) - lightz,
              nl = 1e-5f + cimg::hypot(lx,ly,lz),
              factor = std::max((-lx*nx - ly*ny - lz*nz)/(norm*nl),(tpfloat)0);
            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
          }
        } else {
          const unsigned int
            lw2 = light_texture._width/2 - 1,
            lh2 = light_texture._height/2 - 1;
          lightprops.assign(vertices._width,2);
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096))
          cimg_forX(lightprops,l) {
            const tpfloat
              nx = vertices_normals(l,0),
              ny = vertices_normals(l,1),
              nz = vertices_normals(l,2),
              norm = 1e-5f + cimg::hypot(nx,ny,nz),
              nnx = nx/norm,
              nny = ny/norm;
            lightprops(l,0) = lw2*(1 + nnx);
            lightprops(l,1) = lh2*(1 + nny);
          }
        }
      } break;
      }

      // Draw visible primitives
      const CImg<tc> default_color(1,_spectrum,1,1,(tc)200);
      CImg<_to> _opacity;

      for (unsigned int l = 0; l<nb_visibles; ++l) {
        const unsigned int n_primitive = visibles(permutations(l));
        const CImg<tf>& primitive = primitives[n_primitive];
        const CImg<tc>
          &__color = n_primitive<colors._width?colors[n_primitive]:CImg<tc>(),
          _color = (__color && __color.size()!=_spectrum && __color._spectrum<_spectrum)?
            __color.get_resize(-100,-100,-100,_spectrum,0):CImg<tc>(),
          &color = _color?_color:(__color?__color:default_color);
        const tc *const pcolor = color._data;
        float opacity = __draw_object3d(opacities,n_primitive,_opacity);
        if (_opacity.is_empty()) opacity*=g_opacity;

#ifdef cimg_use_board
        LibBoard::Board &board = *(LibBoard::Board*)pboard;
#endif

        switch (primitive.size()) {
        case 1 : { // Colored point or sprite
          const unsigned int n0 = (unsigned int)primitive[0];
          const int x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1));

          if (_opacity.is_empty()) { // Scalar opacity

            if (color.size()==_spectrum) { // Colored point
              draw_point(x0,y0,pcolor,opacity);

#ifdef cimg_use_board
              if (pboard) {
                board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
                board.drawDot((float)x0,height()-(float)y0);
              }
#endif
            } else { // Sprite
              const tpfloat z = Z + vertices(n0,2);
              const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1);
              const unsigned int
                _sw = (unsigned int)(color._width*factor),
                _sh = (unsigned int)(color._height*factor),
                sw = _sw?_sw:1, sh = _sh?_sh:1;
              const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2;
              if (sw<=3*_width/2 && sh<=3*_height/2 &&
                  (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2<width() || ny0 + (int)sh/2>=0 || ny0 - (int)sh/2<height())) {
                const CImg<tc>
                  _sprite = (sw!=color._width || sh!=color._height)?
                    color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<tc>(),
                  &sprite = _sprite?_sprite:color;
                draw_image(nx0,ny0,sprite,opacity);

#ifdef cimg_use_board
                if (pboard) {
                  board.setPenColorRGBi(128,128,128);
                  board.setFillColor(LibBoard::Color::Null);
                  board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh);
                }
#endif
              }
            }
          } else { // Opacity mask
            const tpfloat z = Z + vertices(n0,2);
            const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1);
            const unsigned int
              _sw = (unsigned int)(std::max(color._width,_opacity._width)*factor),
              _sh = (unsigned int)(std::max(color._height,_opacity._height)*factor),
              sw = _sw?_sw:1, sh = _sh?_sh:1;
            const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2;
            if (sw<=3*_width/2 && sh<=3*_height/2 &&
                (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2<width() || ny0 + (int)sh/2>=0 || ny0 - (int)sh/2<height())) {
              const CImg<tc>
                _sprite = (sw!=color._width || sh!=color._height)?
                  color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<tc>(),
                &sprite = _sprite?_sprite:color;
              const CImg<_to>
                _nopacity = (sw!=_opacity._width || sh!=_opacity._height)?
                  _opacity.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<_to>(),
                &nopacity = _nopacity?_nopacity:_opacity;
              draw_image(nx0,ny0,sprite,nopacity,g_opacity);

#ifdef cimg_use_board
              if (pboard) {
                board.setPenColorRGBi(128,128,128);
                board.setFillColor(LibBoard::Color::Null);
                board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh);
              }
#endif
            }
          }
        } break;
        case 2 : { // Colored line
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1];
          const int
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1));
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale;
          if (render_type) {
            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity);
            else draw_line(x0,y0,x1,y1,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,x1,height() - (float)y1);
            }
#endif
          } else {
            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
            }
#endif
          }
        } break;
        case 5 : { // Colored sphere
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1],
            is_wireframe = (unsigned int)primitive[2];
          const float
            Xc = 0.5f*((float)vertices(n0,0) + (float)vertices(n1,0)),
            Yc = 0.5f*((float)vertices(n0,1) + (float)vertices(n1,1)),
            Zc = 0.5f*((float)vertices(n0,2) + (float)vertices(n1,2)),
            zc = Z + Zc + _focale,
            xc = X + Xc*(absfocale?absfocale/zc:1),
            yc = Y + Yc*(absfocale?absfocale/zc:1),
            radius = 0.5f*cimg::hypot(vertices(n1,0) - vertices(n0,0),
                                      vertices(n1,1) - vertices(n0,1),
                                      vertices(n1,2) - vertices(n0,2))*(absfocale?absfocale/zc:1);
          switch (render_type) {
          case 0 :
            draw_point((int)xc,(int)yc,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawDot(xc,height() - yc);
            }
#endif
            break;
          case 1 :
            draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.setFillColor(LibBoard::Color::Null);
              board.drawCircle(xc,height() - yc,radius);
            }
#endif
            break;
          default :
            if (is_wireframe) draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U);
            else draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              if (!is_wireframe) board.fillCircle(xc,height() - yc,radius);
              else {
                board.setFillColor(LibBoard::Color::Null);
                board.drawCircle(xc,height() - yc,radius);
              }
            }
#endif
            break;
          }
        } break;
        case 6 : { // Textured line
          if (!__color) {
            if (render_type==5) cimg::mutex(10,0);
            throw CImgArgumentException(_cimg_instance
                                        "draw_object3d(): Undefined texture for line primitive [%u].",
                                        cimg_instance,n_primitive);
          }
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1];
          const int
            tx0 = (int)primitive[2], ty0 = (int)primitive[3],
            tx1 = (int)primitive[4], ty1 = (int)primitive[5],
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1));
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale;
          if (render_type) {
            if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity);
            else draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);
            }
#endif
          } else {
            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,
                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).
              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,
                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
            }
#endif
          }
        } break;
        case 3 : { // Colored triangle
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1],
            n2 = (unsigned int)primitive[2];
          const int
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)),
            x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1));
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale,
            z2 = vertices(n2,2) + Z + _focale;
          switch (render_type) {
          case 0 :
            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).draw_point(x2,y2,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
              board.drawDot((float)x2,height() - (float)y2);
            }
#endif
            break;
          case 1 :
            if (zbuffer)
              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,pcolor,opacity).
                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity);
            else
              draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x0,y0,x2,y2,pcolor,opacity).
                draw_line(x1,y1,x2,y2,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);
              board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2);
              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);
            }
#endif
            break;
          case 2 :
            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity);
            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
            }
#endif
            break;
          case 3 :
            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l));
            else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l));

#ifdef cimg_use_board
            if (pboard) {
              const float lp = std::min(lightprops(l),1.f);
              board.setPenColorRGBi((unsigned char)(color[0]*lp),
                                     (unsigned char)(color[1]*lp),
                                     (unsigned char)(color[2]*lp),
                                     (unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
            }
#endif
            break;
          case 4 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,
                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);
            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi((unsigned char)(color[0]),
                                     (unsigned char)(color[1]),
                                     (unsigned char)(color[2]),
                                     (unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0),
                                         (float)x1,height() - (float)y1,lightprops(n1),
                                         (float)x2,height() - (float)y2,lightprops(n2));
            }
#endif
            break;
          case 5 : {
            const unsigned int
              lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)),
              lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)),
              lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1));
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
            else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity);

#ifdef cimg_use_board
            if (pboard) {
              const float
                l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n0,1)))),
                l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n1,1)))),
                l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n2,1))));
              board.setPenColorRGBi((unsigned char)(color[0]),
                                     (unsigned char)(color[1]),
                                     (unsigned char)(color[2]),
                                     (unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,
                                         (float)x1,height() - (float)y1,l1,
                                         (float)x2,height() - (float)y2,l2);
            }
#endif
          } break;
          }
        } break;
        case 4 : { // Colored quadrangle
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1],
            n2 = (unsigned int)primitive[2],
            n3 = (unsigned int)primitive[3];
          const int
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)),
            x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)),
            x3 = cimg::uiround(projections(n3,0)), y3 = cimg::uiround(projections(n3,1)),
            xc = (x0 + x1 + x2 + x3)/4, yc = (y0 + y1 + y2 + y3)/4;
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale,
            z2 = vertices(n2,2) + Z + _focale,
            z3 = vertices(n3,2) + Z + _focale,
            zc = (z0 + z1 + z2 + z3)/4;

          switch (render_type) {
          case 0 :
            draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).
              draw_point(x2,y2,pcolor,opacity).draw_point(x3,y3,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
              board.drawDot((float)x2,height() - (float)y2);
              board.drawDot((float)x3,height() - (float)y3);
            }
#endif
            break;
          case 1 :
            if (zbuffer)
              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity).
                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,pcolor,opacity).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,pcolor,opacity);
            else
              draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x1,y1,x2,y2,pcolor,opacity).
                draw_line(x2,y2,x3,y3,pcolor,opacity).draw_line(x3,y3,x0,y0,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);
              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);
              board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3);
              board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0);
            }
#endif
            break;
          case 2 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity);
            else
              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity).draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x2,height() - (float)y2,
                                 (float)x3,height() - (float)y3);
            }
#endif
            break;
          case 3 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity,lightprops(l));
            else
              _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)).
                _draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity,lightprops(l));

#ifdef cimg_use_board
            if (pboard) {
              const float lp = std::min(lightprops(l),1.f);
              board.setPenColorRGBi((unsigned char)(color[0]*lp),
                                     (unsigned char)(color[1]*lp),
                                     (unsigned char)(color[2]*lp),(unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x2,height() - (float)y2,
                                 (float)x3,height() - (float)y3);
            }
#endif
            break;
          case 4 : {
            const float
              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3),
              lightpropc = (lightprop0 + lightprop1 + lightprop2 + lightprop2)/4;
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,xc,yc,zc,pcolor,lightprop0,lightprop1,lightpropc,opacity).
              draw_triangle(zbuffer,x1,y1,z1,x2,y2,z2,xc,yc,zc,pcolor,lightprop1,lightprop2,lightpropc,opacity).
              draw_triangle(zbuffer,x2,y2,z2,x3,y3,z3,xc,yc,zc,pcolor,lightprop2,lightprop3,lightpropc,opacity).
                draw_triangle(zbuffer,x3,y3,z3,x0,y0,z0,xc,yc,zc,pcolor,lightprop3,lightprop0,lightpropc,opacity);
            else
              draw_triangle(x0,y0,x1,y1,xc,yc,pcolor,lightprop0,lightprop1,lightpropc,opacity).
              draw_triangle(x1,y1,x2,y2,xc,yc,pcolor,lightprop1,lightprop2,lightpropc,opacity).
              draw_triangle(x2,y2,x3,y3,xc,yc,pcolor,lightprop2,lightprop3,lightpropc,opacity).
                draw_triangle(x3,y3,x0,y0,xc,yc,pcolor,lightprop3,lightprop0,lightpropc,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi((unsigned char)(color[0]),
                                     (unsigned char)(color[1]),
                                     (unsigned char)(color[2]),
                                     (unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,
                                         (float)x1,height() - (float)y1,lightprop1,
                                         (float)x2,height() - (float)y2,lightprop2);
              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,
                                         (float)x2,height() - (float)y2,lightprop2,
                                         (float)x3,height() - (float)y3,lightprop3);
            }
#endif
          } break;
          case 5 : {
            const unsigned int
              lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)),
              lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)),
              lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1)),
              lx3 = (unsigned int)cimg::uiround(lightprops(n3,0)), ly3 = (unsigned int)cimg::uiround(lightprops(n3,1)),
              lxc = (lx0 + lx1 + lx2 + lx3)/4, lyc = (ly0 + ly1 + ly2 + ly3)/4;
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,xc,yc,zc,pcolor,light_texture,lx0,ly0,lx1,ly1,lxc,lyc,opacity).
              draw_triangle(zbuffer,x1,y1,z1,x2,y2,z2,xc,yc,zc,pcolor,light_texture,lx1,ly1,lx2,ly2,lxc,lyc,opacity).
              draw_triangle(zbuffer,x2,y2,z2,x3,y3,z3,xc,yc,zc,pcolor,light_texture,lx2,ly2,lx3,ly3,lxc,lyc,opacity).
                draw_triangle(zbuffer,x3,y3,z3,x0,y0,z0,xc,yc,zc,pcolor,light_texture,lx3,ly3,lx0,ly0,lxc,lyc,opacity);
            else
              draw_triangle(x0,y0,x1,y1,xc,yc,pcolor,light_texture,lx0,ly0,lx1,ly1,lxc,lyc,opacity).
              draw_triangle(x1,y1,x2,y2,xc,yc,pcolor,light_texture,lx1,ly1,lx2,ly2,lxc,lyc,opacity).
              draw_triangle(x2,y2,x3,y3,xc,yc,pcolor,light_texture,lx2,ly2,lx3,ly3,lxc,lyc,opacity).
                draw_triangle(x3,y3,x0,y0,xc,yc,pcolor,light_texture,lx3,ly3,lx0,ly0,lxc,lyc,opacity);

#ifdef cimg_use_board
            if (pboard) {
              const float
                l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))),
                l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))),
                l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))),
                l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3)));
              board.setPenColorRGBi((unsigned char)(color[0]),
                                     (unsigned char)(color[1]),
                                     (unsigned char)(color[2]),
                                     (unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,
                                         (float)x1,height() - (float)y1,l1,
                                         (float)x2,height() - (float)y2,l2);
              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,
                                         (float)x2,height() - (float)y2,l2,
                                         (float)x3,height() - (float)y3,l3);
            }
#endif
          } break;
          }
        } break;
        case 9 : { // Textured triangle
          if (!__color) {
            if (render_type==5) cimg::mutex(10,0);
            throw CImgArgumentException(_cimg_instance
                                        "draw_object3d(): Undefined texture for triangle primitive [%u].",
                                        cimg_instance,n_primitive);
          }
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1],
            n2 = (unsigned int)primitive[2];
          const int
            tx0 = (int)primitive[3], ty0 = (int)primitive[4],
            tx1 = (int)primitive[5], ty1 = (int)primitive[6],
            tx2 = (int)primitive[7], ty2 = (int)primitive[8],
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)),
            x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1));
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale,
            z2 = vertices(n2,2) + Z + _focale;
          switch (render_type) {
          case 0 :
            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,
                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).
              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,
                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity).
              draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2,
                                                   ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity);
#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
              board.drawDot((float)x2,height() - (float)y2);
            }
#endif
            break;
          case 1 :
            if (zbuffer)
              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).
                draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity).
                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity);
            else
              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).
                draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity).
                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);
              board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2);
              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);
            }
#endif
            break;
          case 2 :
            if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity);
            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
            }
#endif
            break;
          case 3 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l));
            else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l));

#ifdef cimg_use_board
            if (pboard) {
              const float lp = std::min(lightprops(l),1.f);
              board.setPenColorRGBi((unsigned char)(128*lp),
                                    (unsigned char)(128*lp),
                                    (unsigned char)(128*lp),
                                    (unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
            }
#endif
            break;
          case 4 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            lightprops(n0),lightprops(n1),lightprops(n2),opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0),
                                        (float)x1,height() - (float)y1,lightprops(n1),
                                        (float)x2,height() - (float)y2,lightprops(n2));
            }
#endif
            break;
          case 5 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
                            (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1),
                            (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1),
                            (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1),
                            opacity);
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
                            (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1),
                            (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1),
                            (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1),
                            opacity);

#ifdef cimg_use_board
            if (pboard) {
              const float
                l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n0,1)))),
                l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n1,1)))),
                l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))),
                                   (int)(light_texture.height()/2*(1 + lightprops(n2,1))));
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,
                                        (float)x1,height() - (float)y1,l1,
                                        (float)x2,height() - (float)y2,l2);
            }
#endif
            break;
          }
        } break;
        case 12 : { // Textured quadrangle
          if (!__color) {
            if (render_type==5) cimg::mutex(10,0);
            throw CImgArgumentException(_cimg_instance
                                        "draw_object3d(): Undefined texture for quadrangle primitive [%u].",
                                        cimg_instance,n_primitive);
          }
          const unsigned int
            n0 = (unsigned int)primitive[0],
            n1 = (unsigned int)primitive[1],
            n2 = (unsigned int)primitive[2],
            n3 = (unsigned int)primitive[3];
          const int
            tx0 = (int)primitive[4], ty0 = (int)primitive[5],
            tx1 = (int)primitive[6], ty1 = (int)primitive[7],
            tx2 = (int)primitive[8], ty2 = (int)primitive[9],
            tx3 = (int)primitive[10], ty3 = (int)primitive[11],
            x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)),
            x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)),
            x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)),
            x3 = cimg::uiround(projections(n3,0)), y3 = cimg::uiround(projections(n3,1));
          const float
            z0 = vertices(n0,2) + Z + _focale,
            z1 = vertices(n1,2) + Z + _focale,
            z2 = vertices(n2,2) + Z + _focale,
            z3 = vertices(n3,2) + Z + _focale;

          switch (render_type) {
          case 0 :
            draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0,
                                                 ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity).
              draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1,
                                                   ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity).
              draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2,
                                                   ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity).
              draw_point(x3,y3,color.get_vector_at(tx3<=0?0:tx3>=color.width()?color.width() - 1:tx3,
                                                   ty3<=0?0:ty3>=color.height()?color.height() - 1:ty3)._data,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawDot((float)x0,height() - (float)y0);
              board.drawDot((float)x1,height() - (float)y1);
              board.drawDot((float)x2,height() - (float)y2);
              board.drawDot((float)x3,height() - (float)y3);
            }
#endif
            break;
          case 1 :
            if (zbuffer)
              draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).
                draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity).
                draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity).
                draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity);
            else
              draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity).
                draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity).
                draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity).
                draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1);
              board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2);
              board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3);
              board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0);
            }
#endif
            break;
          case 2 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity);
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity).
                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x2,height() - (float)y2,
                                 (float)x3,height() - (float)y3);
            }
#endif
            break;
          case 3 :
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l));
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)).
                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l));

#ifdef cimg_use_board
            if (pboard) {
              const float lp = std::min(lightprops(l),1.f);
              board.setPenColorRGBi((unsigned char)(128*lp),
                                     (unsigned char)(128*lp),
                                     (unsigned char)(128*lp),
                                     (unsigned char)(opacity*255));
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x1,height() - (float)y1,
                                 (float)x2,height() - (float)y2);
              board.fillTriangle((float)x0,height() - (float)y0,
                                 (float)x2,height() - (float)y2,
                                 (float)x3,height() - (float)y3);
            }
#endif
            break;
          case 4 : {
            const float
              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            lightprop0,lightprop1,lightprop2,opacity).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,
                              lightprop0,lightprop2,lightprop3,opacity);
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            lightprop0,lightprop1,lightprop2,opacity).
                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,
                              lightprop0,lightprop2,lightprop3,opacity);

#ifdef cimg_use_board
            if (pboard) {
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0,
                                         (float)x1,height() - (float)y1,lightprop1,
                                         (float)x2,height() - (float)y2,lightprop2);
              board.fillGouraudTriangle((float)x0,height()  -(float)y0,lightprop0,
                                         (float)x2,height() - (float)y2,lightprop2,
                                         (float)x3,height() - (float)y3,lightprop3);
            }
#endif
          } break;
          case 5 : {
            const unsigned int
              lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)),
              lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)),
              lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1)),
              lx3 = (unsigned int)cimg::uiround(lightprops(n3,0)), ly3 = (unsigned int)cimg::uiround(lightprops(n3,1));
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,
                            light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);
            else
              draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,
                            light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).
                draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,
                            light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);
#ifdef cimg_use_board
            if (pboard) {
              const float
                l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))),
                l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))),
                l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))),
                l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3)));
              board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255));
              board.fillGouraudTriangle((float)x0,height() - (float)y0,l0,
                                         (float)x1,height() - (float)y1,l1,
                                         (float)x2,height() - (float)y2,l2);
              board.fillGouraudTriangle((float)x0,height()  -(float)y0,l0,
                                         (float)x2,height() - (float)y2,l2,
                                         (float)x3,height() - (float)y3,l3);
            }
#endif
          } break;
          }
        } break;
        }
      }
      if (render_type==5) cimg::mutex(10,0);
      return *this;

Project: CImg
File: CImg.h

    **/
    CImgList<Tfloat> get_hessian(const char *const axes=0) const {
      CImgList<Tfloat> res;
      const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
      if (!axes) naxes = _depth>1?def_axes3d:def_axes2d;
      const unsigned int lmax = (unsigned int)std::strlen(naxes);
      if (lmax%2)
        throw CImgArgumentException(_cimg_instance
                                    "get_hessian(): Invalid specified axes '%s'.",
                                    cimg_instance,
                                    naxes);

      res.assign(lmax/2,_width,_height,_depth,_spectrum);
      if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3D

        cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 &&
                                                       _spectrum>=2))
        cimg_forC(*this,c) {
          const ulongT off = (ulongT)c*_width*_height*_depth;
          Tfloat
            *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off,
            *ptrd3 = res[3]._data + off, *ptrd4 = res[4]._data + off, *ptrd5 = res[5]._data + off;
          CImg_3x3x3(I,Tfloat);
          cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
            *(ptrd0++) = Ipcc + Incc - 2*Iccc;          // Ixx
            *(ptrd1++) = (Ippc + Innc - Ipnc - Inpc)/4; // Ixy
            *(ptrd2++) = (Ipcp + Incn - Ipcn - Incp)/4; // Ixz
            *(ptrd3++) = Icpc + Icnc - 2*Iccc;          // Iyy
            *(ptrd4++) = (Icpp + Icnn - Icpn - Icnp)/4; // Iyz
            *(ptrd5++) = Iccn + Iccp - 2*Iccc;          // Izz
          }
        }
      } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // 2D
        cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                           cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 && _depth*_spectrum>=2))
        cimg_forZC(*this,z,c) {
          const ulongT off = (ulongT)c*_width*_height*_depth + z*_width*_height;
          Tfloat *ptrd0 = res[0]._data + off, *ptrd1 = res[1]._data + off, *ptrd2 = res[2]._data + off;
          CImg_3x3(I,Tfloat);
          cimg_for3x3(*this,x,y,z,c,I,Tfloat) {
            *(ptrd0++) = Ipc + Inc - 2*Icc;         // Ixx
            *(ptrd1++) = (Ipp + Inn - Ipn - Inp)/4; // Ixy
            *(ptrd2++) = Icp + Icn - 2*Icc;         // Iyy
          }
        }
      } else for (unsigned int l = 0; l<lmax; ) { // Version with custom axes
          const unsigned int l2 = l/2;
          char axis1 = naxes[l++], axis2 = naxes[l++];
          if (axis1>axis2) cimg::swap(axis1,axis2);
          bool valid_axis = false;
          if (axis1=='x' && axis2=='x') { // Ixx
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 && _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Ipc + Inc - 2*Icc;
            }
          }
          else if (axis1=='x' && axis2=='y') { // Ixy
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 &&
                                              _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipp + Inn - Ipn - Inp)/4;
            }
          }
          else if (axis1=='x' && axis2=='z') { // Ixz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 &&
                                                           _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Ipcp + Incn - Ipcn - Incp)/4;
            }
          }
          else if (axis1=='y' && axis2=='y') { // Iyy
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_collapse(2)
                               cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 &&
                                              _depth*_spectrum>=2))
            cimg_forZC(*this,z,c) {
              Tfloat *ptrd = res[l2].data(0,0,z,c);
              CImg_3x3(I,Tfloat);
              cimg_for3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Icp + Icn - 2*Icc;
            }
          }
          else if (axis1=='y' && axis2=='z') { // Iyz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 &&
                                                           _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = (Icpp + Icnn - Icpn - Icnp)/4;
            }
          }
          else if (axis1=='z' && axis2=='z') { // Izz
            valid_axis = true;
            cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 &&
                                                           _spectrum>=2))
            cimg_forC(*this,c) {
              Tfloat *ptrd = res[l2].data(0,0,0,c);
              CImg_3x3x3(I,Tfloat);
              cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Iccn + Iccp - 2*Iccc;
            }
          }
          else if (!valid_axis)
            throw CImgArgumentException(_cimg_instance
                                        "get_hessian(): Invalid specified axes '%s'.",
                                        cimg_instance,
                                        naxes);
        }
      return res;

Project: CImg
File: CImg.h

    **/
    int window_width() const {
      return (int)_window_width;

Project: CImg
File: CImg.h


      void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) {
        const unsigned int siz = _cimg_mp_size(pos);
        if (siz>24) CImg<ulongT>::vector((ulongT)mp_self_map_vector_v,pos,siz,(ulongT)op,arg1).move_to(code);
        else {
          code.insert(siz);
          for (unsigned int k = 1; k<=siz; ++k)
            CImg<ulongT>::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]);
        }

Project: CImg
File: CImg.h


    CImg<T>& _load_inr(std::FILE *const file, const char *const filename, float *const voxel_size) {
#define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
     if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
        Ts *xval, *const val = new Ts[(size_t)fopt[0]*fopt[3]]; \
        cimg_forYZ(*this,y,z) { \
            cimg::fread(val,fopt[0]*fopt[3],nfile); \
            if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
            xval = val; cimg_forX(*this,x) cimg_forC(*this,c) (*this)(x,y,z,c) = (T)*(xval++); \
          } \
        delete[] val; \
        loaded = true; \
      }

      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_inr(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      int fopt[8], endian = cimg::endianness()?1:0;
      bool loaded = false;
      if (voxel_size) voxel_size[0] = voxel_size[1] = voxel_size[2] = 1;
      _load_inr_header(nfile,fopt,voxel_size);
      assign(fopt[0],fopt[1],fopt[2],fopt[3]);
      _cimg_load_inr_case(0,0,8,unsigned char);
      _cimg_load_inr_case(0,1,8,char);
      _cimg_load_inr_case(0,0,16,unsigned short);
      _cimg_load_inr_case(0,1,16,short);
      _cimg_load_inr_case(0,0,32,unsigned int);
      _cimg_load_inr_case(0,1,32,int);
      _cimg_load_inr_case(1,0,32,float);
      _cimg_load_inr_case(1,1,32,float);
      _cimg_load_inr_case(1,0,64,double);
      _cimg_load_inr_case(1,1,64,double);
      if (!loaded) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_inr(): Unknown pixel type defined in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      if (!file) cimg::fclose(nfile);
      return *this;

Project: CImg
File: CImg.h

      static const char* format() { return cimg_fuint64; }

Project: CImg
File: CImg.h

    **/
    CImg<T> operator+() const {
      return CImg<T>(*this,false);

Project: CImg
File: CImg.h


      static double mp_ellipse(_cimg_math_parser& mp) {
        const unsigned int i_end = (unsigned int)mp.opcode[2];
        unsigned int ind = (unsigned int)mp.opcode[3];
        if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.listin.width());
        CImg<T> &img = ind==~0U?mp.imgout:mp.listout[ind];
        CImg<T> color(img._spectrum,1,1,1,0);
        bool is_invalid_arguments = false, is_outlined = false;
        float r1 = 0, r2 = 0, angle = 0, opacity = 1;
        unsigned int i = 4, pattern = ~0U;
        int x0 = 0, y0 = 0;
        if (i>=i_end) is_invalid_arguments = true;
        else {
          x0 = (int)cimg::round(_mp_arg(i++));
          if (i>=i_end) is_invalid_arguments = true;
          else {
            y0 = (int)cimg::round(_mp_arg(i++));
            if (i>=i_end) is_invalid_arguments = true;
            else {
              r1 = (float)_mp_arg(i++);
              if (i>=i_end) r2 = r1;
              else {
                r2 = (float)_mp_arg(i++);
                if (i<i_end) {
                  angle = (float)_mp_arg(i++);
                  if (i<i_end) {
                    opacity = (float)_mp_arg(i++);
                    if (r1<0 && r2<0) {
                      pattern = (unsigned int)_mp_arg(i++);
                      is_outlined = true;
                      r1 = -r1; r2 = -r2;
                    }
                    if (i<i_end) {
                      cimg_forX(color,k) if (i<i_end) color[k] = (T)_mp_arg(i++);
                      else { color.resize(k,1,1,1,-1); break; }
                      color.resize(img._spectrum,1,1,1,0,2);
                    }
                  }
                }
              }
            }
          }
        }
        if (!is_invalid_arguments) {
          if (is_outlined) img.draw_ellipse(x0,y0,r1,r2,angle,color._data,opacity,pattern);
          else img.draw_ellipse(x0,y0,r1,r2,angle,color._data,opacity);
        } else {
          CImg<doubleT> args(i_end - 4);
          cimg_forX(args,k) args[k] = _mp_arg(4 + k);
          if (ind==~0U)
            throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'ellipse()': "
                                        "Invalid arguments '%s'. ",
                                        mp.imgin.pixel_type(),args.value_string()._data);
          else
            throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'ellipse()': "
                                        "Invalid arguments '#%u%s%s'. ",
                                        mp.imgin.pixel_type(),ind,args._width?",":"",args.value_string()._data);
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

      static unsigned short min() { return 0; }

Project: CImg
File: CImg.h

    **/
    double magnitude(const int magnitude_type=2) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "magnitude(): Empty instance.",
                                    cimg_instance);
      double res = 0;
      switch (magnitude_type) {
      case -1 : {
        cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; }
      } break;
      case 1 : {
        cimg_for(*this,ptrs,T) res+=(double)cimg::abs(*ptrs);
      } break;
      default : {
        cimg_for(*this,ptrs,T) res+=(double)cimg::sqr(*ptrs);
        res = (double)std::sqrt(res);
      }
      }
      return res;

Project: CImg
File: CImg.h

    template<typename tp, typename tc>
    CImg<floatT> get_object3dtoCImg3d(const CImgList<tp>& primitives,
                                      const CImgList<tc>& colors,
                                      const bool full_check=true) const {
      CImgList<T> opacities;
      return get_object3dtoCImg3d(primitives,colors,opacities,full_check);

Project: CImg
File: CImg.h

      static short min() { return ~max(); }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& erode(const CImg<t>& kernel, const bool boundary_conditions=true,
                   const bool is_real=false) {
      if (is_empty() || !kernel) return *this;
      return get_erode(kernel,boundary_conditions,is_real).move_to(*this);

Project: CImg
File: CImg.h


      static double mp_pow3(_cimg_math_parser& mp) {
        const double val = _mp_arg(2);
        return val*val*val;

Project: CImg
File: CImg.h

    template<typename tf, typename tc>
    CImg<floatT> get_projections3d(CImgList<tf>& primitives, CImgList<tc>& colors,
                                   const unsigned int x0, const unsigned int y0, const unsigned int z0,
                                   const bool normalize_colors=false) const {
      float m = 0, M = 0, delta = 1;
      if (normalize_colors) { m = (float)min_max(M); delta = 255/(m==M?1:M-m); }
      const unsigned int
        _x0 = (x0>=_width)?_width - 1:x0,
        _y0 = (y0>=_height)?_height - 1:y0,
        _z0 = (z0>=_depth)?_depth - 1:z0;
      CImg<tc> img_xy, img_xz, img_yz;
      if (normalize_colors) {
        ((get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1)-=m)*=delta).move_to(img_xy);
        ((get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_width,_depth,1,-100,-1).
          move_to(img_xz);
        ((get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_height,_depth,1,-100,-1).
          move_to(img_yz);
      } else {
        get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1).move_to(img_xy);
        get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1).move_to(img_xz);
        get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).resize(_height,_depth,1,-100,-1).move_to(img_yz);
      }
      CImg<floatT> points(12,3,1,1,
                          0,_width - 1,_width - 1,0,   0,_width - 1,_width - 1,0, _x0,_x0,_x0,_x0,
                          0,0,_height - 1,_height - 1, _y0,_y0,_y0,_y0,       0,_height - 1,_height - 1,0,
                          _z0,_z0,_z0,_z0,         0,0,_depth - 1,_depth - 1, 0,0,_depth - 1,_depth - 1);
      primitives.assign();
      CImg<tf>::vector(0,1,2,3,0,0,img_xy._width - 1,0,img_xy._width - 1,img_xy._height - 1,0,img_xy._height - 1).
        move_to(primitives);
      CImg<tf>::vector(4,5,6,7,0,0,img_xz._width - 1,0,img_xz._width - 1,img_xz._height - 1,0,img_xz._height - 1).
        move_to(primitives);
      CImg<tf>::vector(8,9,10,11,0,0,img_yz._width - 1,0,img_yz._width - 1,img_yz._height - 1,0,img_yz._height - 1).
        move_to(primitives);
      colors.assign();
      img_xy.move_to(colors);
      img_xz.move_to(colors);
      img_yz.move_to(colors);
      return points;

Project: CImg
File: CImg.h


      static double mp_complex_div_sv(_cimg_math_parser& mp) {
        const double
          *ptr2 = &_mp_arg(3) + 1,
          r1 = _mp_arg(2),
          r2 = *(ptr2++), i2 = *ptr2;
        double *ptrd = &_mp_arg(1) + 1;
        const double denom = r2*r2 + i2*i2;
        *(ptrd++) = r1*r2/denom;
        *ptrd =  -r1*i2/denom;
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

      }
      static bool is_nan(const long double val) {
#ifdef isnan
        return (bool)isnan(val);
#else
        return !(val==val);
#endif

Project: CImg
File: CImg.h

          current CImgList instance into it.
        Images of the list are appended in a single temporarly image for visualization purposes.
        The function returns when a key is pressed or the display window is closed by the user.
    **/
    const CImgList<T>& display(CImgDisplay &disp, const bool display_info,
                               const char axis='x', const float align=0,

Project: CImg
File: CImg.h


      static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) {
        double &val = _mp_arg(1);
        return val = (double)((longT)val>>(unsigned int)_mp_arg(2));

Project: CImg
File: CImg.h

    //! Load image from a RGBA file \newinstance.
    static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
      return CImg<T>().load_rgba(filename,dimw,dimh);

Project: CImg
File: CImg.h

    **/
    longT offset(const int x, const int y=0, const int z=0, const int c=0) const {
      return x + (longT)y*_width + (longT)z*_width*_height + (longT)c*_width*_height*_depth;

Project: CImg
File: CImg.h

    **/
    CImgList<T>& operator=(const CImgDisplay& disp) {
      return assign(disp);

Project: CImg
File: CImg.h

      return remove(_width - 1);
    }

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& dilate(const CImg<t>& kernel, const bool boundary_conditions=true,
                    const bool is_real=false) {
      if (is_empty() || !kernel) return *this;
      return get_dilate(kernel,boundary_conditions,is_real).move_to(*this);

Project: CImg
File: CImg.h


      static double mp_list_set_Ioff_v(_cimg_math_parser& mp) {
        const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
        CImg<T> &img = mp.listout[ind];
        const longT
          off = (longT)_mp_arg(3),
          whd = (longT)img.width()*img.height()*img.depth();
        const double *ptrs = &_mp_arg(1) + 1;
        if (off>=0 && off<whd) {
          const unsigned int vsiz = (unsigned int)mp.opcode[4];
          T *ptrd = &img[off];
          cimg_for_inC(img,0,vsiz - 1,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
        }
        return cimg::type<double>::nan();

Project: CImg
File: CImg.h

    //! Compute the bitwise left rotation of each pixel value \newinstance.
    CImg<T> get_rol(const char *const expression) const {
      return (+*this).rol(expression);

Project: CImg
File: CImg.h


      static double mp_cosh(_cimg_math_parser& mp) {
        return std::cosh(_mp_arg(2));

Project: CImg
File: CImg.h

    template<typename t>
    CImg(const CImg<t>& img, const char *const dimensions):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(img,dimensions);

Project: CImg
File: CImg.h

    //! Resize 3D object to unit size.
    CImg<T> resize_object3d() {
      if (_height!=3 || _depth>1 || _spectrum>1)
        throw CImgInstanceException(_cimg_instance
                                    "resize_object3d(): Instance is not a set of 3D vertices.",
                                    cimg_instance);

      CImg<T> xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2);
      float
        xm, xM = (float)xcoords.max_min(xm),
        ym, yM = (float)ycoords.max_min(ym),
        zm, zM = (float)zcoords.max_min(zm);
      const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
      if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
      return *this;

Project: CImg
File: CImg.h

    template<typename tp>
    const CImg<T>& display_object3d(CImgDisplay &disp,
                                    const CImg<tp>& vertices,
                                    const bool centering=true,
                                    const int render_static=4, const int render_motion=1,
                                    const bool is_double_sided=true, const float focale=700,
                                    const float light_x=0, const float light_y=0, const float light_z=-5e8f,
                                    const float specular_lightness=0.2f, const float specular_shininess=0.1f,
                                    const bool display_axes=true, float *const pose_matrix=0,
                                    const bool exit_on_anykey=false) const {
      return display_object3d(disp,vertices,CImgList<uintT>(),centering,
                              render_static,render_motion,is_double_sided,focale,
                              light_x,light_y,light_z,specular_lightness,specular_shininess,
                              display_axes,pose_matrix,exit_on_anykey);

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_video(const char *const filename, const unsigned int fps=25,
                              const char *codec=0, const bool keep_open=false) const {
      if (is_empty()) { CImgList<T>().save_video(filename,fps,codec,keep_open); return *this; }
      CImgList<T> list;
      get_split('z').move_to(list);
      list.save_video(filename,fps,codec,keep_open);
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<t> get_map(const CImg<t>& colormap, const unsigned int boundary_conditions=0) const {
      const ulongT
        whd = (ulongT)_width*_height*_depth, siz = size(),
        cwhd = (ulongT)colormap._width*colormap._height*colormap._depth,
        cwhd2 = 2*cwhd;
      CImg<t> res(_width,_height,_depth,_spectrum*colormap._spectrum);
      switch (colormap._spectrum) {

      case 1 : { // Optimized for scalars
        switch (boundary_conditions) {
        case 3 : // Mirror
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
          for (longT off = 0; off<(longT)siz; ++off) {
            const ulongT ind = ((ulongT)_data[off])%cwhd2;
            res[off] = colormap[ind<cwhd?ind:cwhd2 - ind - 1];
          }
          break;
        case 2 : // Periodic
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
          for (longT off = 0; off<(longT)siz; ++off) {
            const ulongT ind = (ulongT)_data[off];
            res[off] = colormap[ind%cwhd];
          }
          break;
        case 1 : // Neumann
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
          for (longT off = 0; off<(longT)siz; ++off) {
            const longT ind = (longT)_data[off];
            res[off] = colormap[cimg::cut(ind,(longT)0,(longT)cwhd - 1)];
          } break;
        default : // Dirichlet
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
          for (longT off = 0; off<(longT)siz; ++off) {
            const ulongT ind = (ulongT)_data[off];
            res[off] = ind<cwhd?colormap[ind]:(t)0;
          }
        }
      } break;

      case 2 : { // Optimized for 2D vectors
        const t *const ptrp0 = colormap._data, *const ptrp1 = ptrp0 + cwhd;
        switch (boundary_conditions) {
        case 3 : // Mirror
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,2*c), *const ptrd1 = ptrd0 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT
                _ind = ((ulongT)ptrs[off])%cwhd2,
                ind = _ind<cwhd?_ind:cwhd2 - _ind - 1;
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind];
            }
          } break;
        case 2 : // Periodic
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,2*c), *const ptrd1 = ptrd0 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = ((ulongT)ptrs[off])%cwhd;
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind];
            }
          } break;
        case 1 : // Neumann
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,2*c), *const ptrd1 = ptrd0 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const longT ind = cimg::cut((longT)ptrs[off],(longT)0,(longT)cwhd - 1);
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind];
            }
          } break;
        default : // Dirichlet
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,2*c), *const ptrd1 = ptrd0 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = (ulongT)ptrs[off];
              if (ind<cwhd) { ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind]; }
              else ptrd0[off] = ptrd1[off] = (t)0;
            }
          }
        }
      } break;

      case 3 : { // Optimized for 3D vectors (colors)
        const t *const ptrp0 = colormap._data, *ptrp1 = ptrp0 + cwhd, *ptrp2 = ptrp0 + 2*cwhd;
        switch (boundary_conditions) {
        case 3 : // Mirror
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,3*c), *const ptrd1 = ptrd0 + whd, *const ptrd2 = ptrd1 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT
                _ind = ((ulongT)ptrs[off])%cwhd2,
                ind = _ind<cwhd?_ind:cwhd2 - _ind - 1;
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind]; ptrd2[off] = ptrp2[ind];
            }
          } break;
        case 2 : // Periodic
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,3*c), *const ptrd1 = ptrd0 + whd, *const ptrd2 = ptrd1 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = ((ulongT)ptrs[off])%cwhd;
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind]; ptrd2[off] = ptrp2[ind];
            }
          } break;
        case 1 : // Neumann
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,3*c), *const ptrd1 = ptrd0 + whd, *const ptrd2 = ptrd1 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const longT ind = cimg::cut((longT)ptrs[off],(longT)0,(longT)cwhd - 1);
              ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind]; ptrd2[off] = ptrp2[ind];
            }
          } break;
        default : // Dirichlet
          cimg_forC(*this,c) {
            t *const ptrd0 = res.data(0,0,0,3*c), *const ptrd1 = ptrd0 + whd, *const ptrd2 = ptrd1 + whd;
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = (ulongT)ptrs[off];
              if (ind<cwhd) { ptrd0[off] = ptrp0[ind]; ptrd1[off] = ptrp1[ind]; ptrd2[off] = ptrp2[ind]; }
              else ptrd0[off] = ptrd1[off] = ptrd2[off] = (t)0;
            }
          }
        }
      } break;

      default : { // Generic version
        switch (boundary_conditions) {
        case 3 : // Mirror
          cimg_forC(*this,c) {
            t *const ptrd = res.data(0,0,0,colormap._spectrum*c);
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT
                _ind = ((ulongT)ptrs[off])%cwhd,
                ind = _ind<cwhd?_ind:cwhd2 - _ind - 1;
              t *const _ptrd = ptrd + off;
              const t *const ptrp = &colormap[ind];
              cimg_forC(colormap,k) _ptrd[k*whd] = ptrp[k*cwhd];
            }
          } break;
        case 2 : // Periodic
          cimg_forC(*this,c) {
            t *const ptrd = res.data(0,0,0,colormap._spectrum*c);
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = ((ulongT)ptrs[off])%cwhd;
              t *const _ptrd = ptrd + off;
              const t *const ptrp = &colormap[ind];
              cimg_forC(colormap,k) _ptrd[k*whd] = ptrp[k*cwhd];
            }
          } break;
        case 1 : // Neumann
          cimg_forC(*this,c) {
            t *const ptrd = res.data(0,0,0,colormap._spectrum*c);
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const longT ind = cimg::cut((longT)ptrs[off],(longT)0,(longT)cwhd - 1);
              t *const _ptrd = ptrd + off;
              const t *const ptrp = &colormap[ind];
              cimg_forC(colormap,k) _ptrd[k*whd] = ptrp[k*cwhd];
            }
          } break;
        default : // Dirichlet
          cimg_forC(*this,c) {
            t *const ptrd = res.data(0,0,0,colormap._spectrum*c);
            const T *const ptrs = data(0,0,0,c);
            cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256))
            for (longT off = 0; off<(longT)whd; ++off) {
              const ulongT ind = (ulongT)ptrs[off];
              t *const _ptrd = ptrd + off;
              if (ind<cwhd) {
                const t *const ptrp = &colormap[ind];
                cimg_forC(colormap,k) _ptrd[k*whd] = ptrp[k*cwhd];
              } else cimg_forC(colormap,k) _ptrd[k*whd] = (t)0;
            }
          }
        }
      }
      }
      return res;