Commit message: Fix other issues in 'CImg<T>::load_bmp()'.
CVE: CVE-2018-7641
CWE: CWE-125
Vulnerability description: An issue was discovered in CImg v.220. A heap-based buffer over-read in load_bmp in CImg.h occurs when loading a crafted bmp image, a different vulnerability than CVE-2018-7588. This is in a "32 bits colors" case, aka case 32.

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 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.0f?0.0f:(specular_lightness>1.0f?1.0f:specular_lightness)),
        nspec2 = 1 + (specular_shininess<0.0f?0.0f: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.0f,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.0f,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(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(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(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 : // Segment
        case 6 : {
          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 :  // Triangle
        case 9 : {
          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 : // Rectangle
        case 12 : {
          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(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(nb_visibles>4096))
        for (unsigned int l = 0; l<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),
            rectangle_flag = (psize==4) || (psize==12);
          if (triangle_flag || rectangle_flag) {
            const unsigned int
              i0 = (unsigned int)primitive(0),
              i1 = (unsigned int)primitive(1),
              i2 = (unsigned int)primitive(2),
              i3 = rectangle_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 (rectangle_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(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(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;
        const float opacity = __draw_object3d(opacities,n_primitive,_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 = (int)projections(n0,0), y0 = (int)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);
#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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)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,x1,y1,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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
            x2 = (int)projections(n2,0), y2 = (int)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);
              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)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)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 rectangle
          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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
            x3 = (int)projections(n3,0), y3 = (int)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,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);
              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);
            if (zbuffer)
              draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,lightprop0,lightprop1,lightprop2,opacity).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,lightprop0,lightprop2,lightprop3,opacity);
            else
              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprop0,lightprop1,lightprop2,opacity).
                draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,lightprop0,lightprop2,lightprop3,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)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,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).
                draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity);
            else
              draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity).
                draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,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((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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
            x2 = (int)projections(n2,0), y2 = (int)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);
              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 = (int)projections(n0,0), y0 = (int)projections(n0,1),
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
            x3 = (int)projections(n3,0), y3 = (int)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);
              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)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)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

    template<typename tc>
    CImg<T>& draw_triangle(const int x0, const int y0,
                           const int x1, const int y1,
                           const int x2, const int y2,
                           const CImg<tc>& texture,
                           const int tx0, const int ty0,
                           const int tx1, const int ty1,
                           const int tx2, const int ty2,
                           const float brightness0,
                           const float brightness1,
                           const float brightness2,
                           const float opacity=1) {
      if (is_empty()) return *this;
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_overlapped(texture))
        return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
                             brightness0,brightness1,brightness2,opacity);
      static const T maxval = (T)std::min(cimg::type<T>::max(),cimg::type<tc>::max());
      const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.0f);
      const ulongT
        whd = (ulongT)_width*_height*_depth,
        twh = (ulongT)texture._width*texture._height,
        offx = _spectrum*whd - 1;
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
        ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
        nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
        nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
        nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
      if (ny0>=height() || ny2<0) return *this;
      _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
                          nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
        int
          xleft = xleft0, xright = xright0,
          cleft = cleft0, cright = cright0,
          txleft = txleft0, txright = txright0,
          tyleft = tyleft0, tyright = tyright0;
        if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
        const int
          dx = xright - xleft,
          dc = cright>cleft?cright - cleft:cleft - cright,
          dtx = txright>txleft?txright - txleft:txleft - txright,
          dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
          rc = dx?(cright - cleft)/dx:0,
          rtx = dx?(txright - txleft)/dx:0,
          rty = dx?(tyright - tyleft)/dx:0,
          sc = cright>cleft?1:-1,
          stx = txright>txleft?1:-1,
          sty = tyright>tyleft?1:-1,
          ndc = dc - (dx?dx*(dc/dx):0),
          ndtx = dtx - (dx?dx*(dtx/dx):0),
          ndty = dty - (dx?dx*(dty/dx):0);
        int errc = dx>>1, errtx = errc, errty = errc;
        if (xleft<0 && dx) {
          cleft-=xleft*(cright - cleft)/dx;
          txleft-=xleft*(txright - txleft)/dx;
          tyleft-=xleft*(tyright - tyleft)/dx;
        }
        if (xleft<0) xleft = 0;
        if (xright>=width() - 1) xright = width() - 1;
        T* ptrd = data(xleft,y,0,0);
        if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
          const tc *col = &texture._atXY(txleft,tyleft);
          cimg_forC(*this,c) {
            *ptrd = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
            ptrd+=whd; col+=twh;
          }
          ptrd-=offx;
          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
        } else for (int x = xleft; x<=xright; ++x) {
          const tc *col = &texture._atXY(txleft,tyleft);
          cimg_forC(*this,c) {
            const T val = (T)(cleft<256?cleft**col/256:((512 - cleft)**col + (cleft - 256)*maxval)/256);
            *ptrd = (T)(nopacity*val + *ptrd*copacity);
            ptrd+=whd; col+=twh;
          }
          ptrd-=offx;
          cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
          txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
          tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
        }
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
                         const int x1, const int y1, const float u1, const float v1,
                         const CImg<t>& texture,
                         const int tx0, const int ty0, const int tx1, const int ty1,
                         const float opacity=1,
                         const float precision=4, const unsigned int pattern=~0U,
                         const bool init_hatch=true) {
      if (texture._depth>1 || texture._spectrum<_spectrum)
        throw CImgArgumentException(_cimg_instance
                                    "draw_spline(): Invalid specified texture (%u,%u,%u,%u,%p).",
                                    cimg_instance,
                                    texture._width,texture._height,texture._depth,texture._spectrum,texture._data);
      if (is_empty()) return *this;
      if (is_overlapped(texture))
        return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);
      if (x0==x1 && y0==y1)
        return draw_point(x0,y0,texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0,
                                                      y0<=0?0:y0>=texture.height()?texture.height() - 1:y0),opacity);
      bool ninit_hatch = init_hatch;
      const float
        ax = u0 + u1 + 2*(x0 - x1),
        bx = 3*(x1 - x0) - 2*u0 - u1,
        ay = v0 + v1 + 2*(y0 - y1),
        by = 3*(y1 - y0) - 2*v0 - v1,
        _precision = 1/(cimg::hypot((float)x0 - x1,(float)y0 - y1)*(precision>0?precision:1));
      int ox = x0, oy = y0, otx = tx0, oty = ty0;
      for (float t1 = 0; t1<1; t1+=_precision) {
        const float t2 = t1*t1, t3 = t2*t1;
        const int
          nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
          ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
          ntx = tx0 + (int)((tx1 - tx0)*t1),
          nty = ty0 + (int)((ty1 - ty0)*t1);
        draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
        ninit_hatch = false;
        ox = nx; oy = ny; otx = ntx; oty = nty;
      }
      return draw_line(ox,oy,x1,y1,texture,otx,oty,tx1,ty1,opacity,pattern,false);

Project: CImg
File: CImg.h


      static double mp_isint(_cimg_math_parser& mp) {
        return (double)(cimg::mod(_mp_arg(2),1.0)==0);

Project: CImg
File: CImg.h


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

Project: CImg
File: CImg.h

    **/
    CImg<T> rotate(const float u, const float v, const float w, const float angle,
                   const unsigned int interpolation, const unsigned int boundary_conditions) {
      const float nangle = cimg::mod(angle,360.0f);
      if (nangle==0.0f) return *this;
      return get_rotate(u,v,w,nangle,interpolation,boundary_conditions).move_to(*this);

Project: CImg
File: CImg.h

    //! Convert ascii character to upper case.
    inline char uppercase(const char x) {
      return (char)((x<'a'||x>'z')?x:x - 'a' + 'A');

Project: CImg
File: CImg.h

    template<typename tf, typename t>
    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
                            const unsigned int starting_node, const unsigned int ending_node,
                            CImg<t>& previous_node) {
      if (starting_node>=nb_nodes)
        throw CImgArgumentException("CImg<%s>::dijkstra(): Specified indice of starting node %u is higher "
                                    "than number of nodes %u.",
                                    pixel_type(),starting_node,nb_nodes);
      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
      dist(starting_node) = 0;
      previous_node.assign(1,nb_nodes,1,1,(t)-1);
      previous_node(starting_node) = (t)starting_node;
      CImg<uintT> Q(nb_nodes);
      cimg_forX(Q,u) Q(u) = (unsigned int)u;
      cimg::swap(Q(starting_node),Q(0));
      unsigned int sizeQ = nb_nodes;
      while (sizeQ) {
        // Update neighbors from minimal vertex
        const unsigned int umin = Q(0);
        if (umin==ending_node) sizeQ = 0;
        else {
          const T dmin = dist(umin);
          const T infty = cimg::type<T>::max();
          for (unsigned int q = 1; q<sizeQ; ++q) {
            const unsigned int v = Q(q);
            const T d = (T)distance(v,umin);
            if (d<infty) {
              const T alt = dmin + d;
              if (alt<dist(v)) {
                dist(v) = alt;
                previous_node(v) = (t)umin;
                const T distpos = dist(Q(q));
                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos + 1)/2 - 1)); pos=par)
                  cimg::swap(Q(pos),Q(par));
              }
            }
          }
          // Remove minimal vertex from queue
          Q(0) = Q(--sizeQ);
          const T distpos = dist(Q(0));
          for (unsigned int pos = 0, left = 0, right = 0;
               ((right=2*(pos + 1),(left=right - 1))<sizeQ && distpos>dist(Q(left))) ||
                 (right<sizeQ && distpos>dist(Q(right)));) {
            if (right<sizeQ) {
              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
              else { cimg::swap(Q(pos),Q(right)); pos = right; }
            } else { cimg::swap(Q(pos),Q(left)); pos = left; }
          }
        }
      }
      return dist;

Project: CImg
File: CImg.h


    CImg<T>& _load_pfm(std::FILE *const file, const char *const filename) {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "load_pfm(): Specified filename is (null).",
                                    cimg_instance);

      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      char pfm_type;
      CImg<charT> item(16384,1,1,1,0);
      int W = 0, H = 0, err = 0;
      double scale = 0;
      while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if (cimg_sscanf(item," P%c",&pfm_type)!=1) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pfm(): PFM header not found in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
      if ((err=cimg_sscanf(item," %d %d",&W,&H))<2) {
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.",
                              cimg_instance,
                              filename?filename:"(FILE*)");
      }
      if (err==2) {
        while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile);
        if (cimg_sscanf(item,"%lf",&scale)!=1)
          cimg::warn(_cimg_instance
                     "load_pfm(): SCALE field is undefined in file '%s'.",
                     cimg_instance,
                     filename?filename:"(FILE*)");
      }
      std::fgetc(nfile);
      const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness();
      if (is_color) {
        assign(W,H,1,3,(T)0);
        CImg<floatT> buf(3*W);
        T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2);
        cimg_forY(*this,y) {
          cimg::fread(buf._data,3*W,nfile);
          if (is_inverted) cimg::invert_endianness(buf._data,3*W);
          const float *ptrs = buf._data;
          cimg_forX(*this,x) {
            *(ptr_r++) = (T)*(ptrs++);
            *(ptr_g++) = (T)*(ptrs++);
            *(ptr_b++) = (T)*(ptrs++);
          }
        }
      } else {
        assign(W,H,1,1,(T)0);
        CImg<floatT> buf(W);
        T *ptrd = data(0,0,0,0);
        cimg_forY(*this,y) {
          cimg::fread(buf._data,W,nfile);
          if (is_inverted) cimg::invert_endianness(buf._data,W);
          const float *ptrs = buf._data;
          cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++);
        }
      }
      if (!file) cimg::fclose(nfile);
      return mirror('y');  // Most of the .pfm files are flipped along the y-axis.

Project: CImg
File: CImg.h

    template<typename t>
    CImg<_cimg_Ttfloat> get_solve(const CImg<t>& A) const {
      return CImg<_cimg_Ttfloat>(*this,false).solve(A);

Project: CImg
File: CImg.h

     \param referer Referer used, as a C-string.
     \return Value of \c filename_local.
     \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download.
  **/
  inline char *load_network(const char *const url, char *const filename_local,
                            const unsigned int timeout, const bool try_fallback,
                            const char *const referer) {
    if (!url)
      throw CImgArgumentException("cimg::load_network(): Specified URL is (null).");
    if (!filename_local)
      throw CImgArgumentException("cimg::load_network(): Specified destination string is (null).");

    const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext;
    CImg<char> ext = CImg<char>::string(_ext);
    std::FILE *file = 0;
    *filename_local = 0;
    if (ext._width>16 || !cimg::strncasecmp(ext,"cgi",3)) *ext = 0;
    else cimg::strwindows_reserved(ext);
    do {
      cimg_snprintf(filename_local,256,"%s%c%s%s",
                    cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data);
      if ((file=std_fopen(filename_local,"rb"))!=0) cimg::fclose(file);
    } while (file);

#ifdef cimg_use_curl
    const unsigned int omode = cimg::exception_mode();
    cimg::exception_mode(0);
    try {
      CURL *curl = 0;
      CURLcode res;
      curl = curl_easy_init();
      if (curl) {
        file = cimg::fopen(filename_local,"wb");
        curl_easy_setopt(curl,CURLOPT_URL,url);
        curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0);
        curl_easy_setopt(curl,CURLOPT_WRITEDATA,file);
        curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L);
        curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L);
        curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);
        if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout);
        if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L);
        if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        cimg::fseek(file,0,SEEK_END); // Check if file size is 0.
        const cimg_ulong siz = cimg::ftell(file);
        cimg::fclose(file);
        if (siz>0 && res==CURLE_OK) {
          cimg::exception_mode(omode);
          return filename_local;
        } else std::remove(filename_local);
      }
    } catch (...) { }
    cimg::exception_mode(omode);
    if (!try_fallback) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with libcurl.",url);
#endif

    CImg<char> command((unsigned int)std::strlen(url) + 64);
    cimg::unused(try_fallback);

    // Try with 'curl' first.
    if (timeout) {
      if (referer)
        cimg_snprintf(command,command._width,"%s -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
                      cimg::curl_path(),referer,timeout,filename_local,url);
      else
        cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
                      cimg::curl_path(),timeout,filename_local,url);
    } else {
      if (referer)
        cimg_snprintf(command,command._width,"%s -e %s -f --silent --compressed -o \"%s\" \"%s\"",
                      cimg::curl_path(),referer,filename_local,url);
      else
        cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"",
                      cimg::curl_path(),filename_local,url);
    }
    cimg::system(command);

    if (!(file = std_fopen(filename_local,"rb"))) {

      // Try with 'wget' otherwise.
      if (timeout) {
        if (referer)
          cimg_snprintf(command,command._width,"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                        cimg::wget_path(),referer,timeout,filename_local,url);
        else
          cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                        cimg::wget_path(),timeout,filename_local,url);
      } else {
        if (referer)
          cimg_snprintf(command,command._width,"%s --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                        cimg::wget_path(),referer,filename_local,url);
        else
          cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
                        cimg::wget_path(),filename_local,url);
      }
      cimg::system(command);

      if (!(file = std_fopen(filename_local,"rb")))
        throw CImgIOException("cimg::load_network(): Failed to load file '%s' with external commands "
                              "'wget' or 'curl'.",url);
      cimg::fclose(file);

      // Try gunzip it.
      cimg_snprintf(command,command._width,"%s.gz",filename_local);
      std::rename(filename_local,command);
      cimg_snprintf(command,command._width,"%s --quiet \"%s.gz\"",
                    gunzip_path(),filename_local);
      cimg::system(command);
      file = std_fopen(filename_local,"rb");
      if (!file) {
        cimg_snprintf(command,command._width,"%s.gz",filename_local);
        std::rename(command,filename_local);
        file = std_fopen(filename_local,"rb");
      }
    }
    cimg::fseek(file,0,SEEK_END); // Check if file size is 0.
    if (std::ftell(file)<=0)
      throw CImgIOException("cimg::load_network(): Failed to load URL '%s' with external commands "

Project: CImg
File: CImg.h

    **/
    CImg<T>& rol(const unsigned int n=1) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=32768))
      cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);
      return *this;

Project: CImg
File: CImg.h

    template<typename tfunc>
    static CImg<floatT> streamline(const tfunc& func,
                                   const float x, const float y, const float z,
                                   const float L=256, const float dl=0.1f,
                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=false,
                                   const bool is_oriented_only=false,
                                   const float x0=0, const float y0=0, const float z0=0,
                                   const float x1=0, const float y1=0, const float z1=0) {
      if (dl<=0)
        throw CImgArgumentException("CImg<%s>::streamline(): Invalid specified integration length %g "
                                    "(should be >0).",
                                    pixel_type(),
                                    dl);

      const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1);
      if (L<=0 || (is_bounded && (x<x0 || x>x1 || y<y0 || y>y1 || z<z0 || z>z1))) return CImg<floatT>();
      const unsigned int size_L = (unsigned int)cimg::round(L/dl + 1);
      CImg<floatT> coordinates(size_L,3);
      const float dl2 = dl/2;
      float
        *ptr_x = coordinates.data(0,0),
        *ptr_y = coordinates.data(0,1),
        *ptr_z = coordinates.data(0,2),
        pu = (float)(dl*func(x,y,z,0)),
        pv = (float)(dl*func(x,y,z,1)),
        pw = (float)(dl*func(x,y,z,2)),
        X = x, Y = y, Z = z;

      switch (interpolation_type) {
      case 0 : { // Nearest integer interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          const int
            xi = (int)(X>0?X + 0.5f:X - 0.5f),
            yi = (int)(Y>0?Y + 0.5f:Y - 0.5f),
            zi = (int)(Z>0?Z + 0.5f:Z - 0.5f);
          float
            u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)),
            v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)),
            w = (float)(dl*func((float)xi,(float)yi,(float)zi,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      case 1 : { // First-order interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u = (float)(dl*func(X,Y,Z,0)),
            v = (float)(dl*func(X,Y,Z,1)),
            w = (float)(dl*func(X,Y,Z,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      case 2 : { // Second order interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u0 = (float)(dl2*func(X,Y,Z,0)),
            v0 = (float)(dl2*func(X,Y,Z,1)),
            w0 = (float)(dl2*func(X,Y,Z,2));
          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }
          float
            u = (float)(dl*func(X + u0,Y + v0,Z + w0,0)),
            v = (float)(dl*func(X + u0,Y + v0,Z + w0,1)),
            w = (float)(dl*func(X + u0,Y + v0,Z + w0,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      default : { // Fourth order interpolation.
        cimg_forX(coordinates,x) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u0 = (float)(dl2*func(X,Y,Z,0)),
            v0 = (float)(dl2*func(X,Y,Z,1)),
            w0 = (float)(dl2*func(X,Y,Z,2));
          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }
          float
            u1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,0)),
            v1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,1)),
            w1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,2));
          if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; }
          float
            u2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,0)),
            v2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,1)),
            w2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,2));
          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; }
          float
            u3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,0)),
            v3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,1)),
            w3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,2));
          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; }
          const float
            u = (u0 + u3)/3 + (u1 + u2)/1.5f,
            v = (v0 + v3)/3 + (v1 + v2)/1.5f,
            w = (w0 + w3)/3 + (w1 + w2)/1.5f;
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      }
      }
      if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0);
      return coordinates;

Project: CImg
File: CImg.h


      static double mp_srand0(_cimg_math_parser& mp) {
        cimg::unused(mp);
        return cimg::srand();

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_ixyzc(_cimg_math_parser& mp) {
        const unsigned int
          interpolation = (unsigned int)_mp_arg(6),
          boundary_conditions = (unsigned int)_mp_arg(7);
        const CImg<T> &img = mp.imgin;
        const double
          x = _mp_arg(2), y = _mp_arg(3),
          z = _mp_arg(4), c = _mp_arg(5);
        if (interpolation==0) switch (boundary_conditions) { // Nearest neighbor interpolation
          case 3 : { // Mirror
            const int
              w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(),
              mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2),
              mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2);
            return (double)img(mx<img.width()?mx:w2 - mx - 1,
                               my<img.height()?my:h2 - my - 1,
                               mz<img.depth()?mz:d2 - mz - 1,
                               mc<img.spectrum()?mc:s2 - mc - 1);
          }
          case 2 : // Periodic
            return (double)img(cimg::mod((int)x,img.width()),
                               cimg::mod((int)y,img.height()),
                               cimg::mod((int)z,img.depth()),
                               cimg::mod((int)c,img.spectrum()));
          case 1 : // Neumann
            return (double)img._atXYZC((int)x,(int)y,(int)z,(int)c);
          default : // Dirichlet
            return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,(T)0);
          } else switch (boundary_conditions) { // Linear interpolation
          case 3 : { // Mirror
            const float
              w2 = 2.0f*img.width(), h2 = 2.0f*img.height(), d2 = 2.0f*img.depth(), s2 = 2.0f*img.spectrum(),
              mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2),
              mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2);
            return (double)img._linear_atXYZC(mx<img.width()?mx:w2 - mx - 1,
                                              my<img.height()?my:h2 - my - 1,
                                              mz<img.depth()?mz:d2 - mz - 1,
                                              mc<img.spectrum()?mc:s2 - mc - 1);
          }
          case 2 : // Periodic
            return (double)img._linear_atXYZC(cimg::mod((float)x,(float)img.width()),
                                              cimg::mod((float)y,(float)img.height()),
                                              cimg::mod((float)z,(float)img.depth()),
                                              cimg::mod((float)c,(float)img.spectrum()));
          case 1 : // Neumann
            return (double)img._linear_atXYZC((float)x,(float)y,(float)z,(float)c);
          default : // Dirichlet
            return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,(T)0);
          }

Project: CImg
File: CImg.h

    inline unsigned int& openmp_mode(const unsigned int mode) {
      return _openmp_mode(mode,true);
    }

Project: CImg
File: CImg.h

    **/
    CImg<T>& log10() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=4096))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

    **/
    bool is_CImg3d(const bool full_check=true, char *const error_message=0) const {
      if (error_message) *error_message = 0;

      // Check instance dimension and header.
      if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d has invalid dimensions (%u,%u,%u,%u)",
                                        _width,_height,_depth,_spectrum);
        return false;
      }
      const T *ptrs = _data, *const ptre = end();
      if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||
          !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d header not found");
        return false;
      }
      const unsigned int
        nb_points = cimg::float2uint((float)*(ptrs++)),
        nb_primitives = cimg::float2uint((float)*(ptrs++));

      // Check consistency of number of vertices / primitives.
      if (!full_check) {
        const ulongT minimal_size = 8UL + 3*nb_points + 6*nb_primitives;
        if (_data + minimal_size>ptre) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected",
                                          nb_points,nb_primitives,(unsigned long)size(),(unsigned long)minimal_size);
          return false;
        }
      }

      // Check consistency of vertex data.
      if (!nb_points) {
        if (nb_primitives) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) defines no vertices but %u primitives",
                                          nb_points,nb_primitives,nb_primitives);
          return false;
        }
        if (ptrs!=ptre) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) is an empty object but contains %u value%s "
                                          "more than expected",
                                          nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
          return false;
        }
        return true;
      }
      if (ptrs + 3*nb_points>ptre) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d (%u,%u) defines only %u vertices data",
                                        nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3);
        return false;
      }
      ptrs+=3*nb_points;

      // Check consistency of primitive data.
      if (ptrs==ptre) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d (%u,%u) defines %u vertices but no primitive",
                                        nb_points,nb_primitives,nb_points);
        return false;
      }

      if (!full_check) return true;

      for (unsigned int p = 0; p<nb_primitives; ++p) {
        const unsigned int nb_inds = (unsigned int)*(ptrs++);
        switch (nb_inds) {
        case 1 : { // Point.
          const unsigned int i0 = cimg::float2uint((float)*(ptrs++));
          if (i0>=nb_points) {
            if (error_message) cimg_sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]",
                                            nb_points,nb_primitives,i0,p);
            return false;
          }
        } break;
        case 5 : { // Sphere.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++));
          ptrs+=3;
          if (i0>=nb_points || i1>=nb_points) {
            if (error_message) cimg_sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
                                            "sphere primitive [%u]",
                                            nb_points,nb_primitives,i0,i1,p);
            return false;
          }
        } break;
        case 2 : case 6 : { // Segment.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==6) ptrs+=4;
          if (i0>=nb_points || i1>=nb_points) {
            if (error_message) cimg_sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
                                            "segment primitive [%u]",
                                            nb_points,nb_primitives,i0,i1,p);
            return false;
          }
        } break;
        case 3 : case 9 : { // Triangle.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++)),
            i2 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==9) ptrs+=6;
          if (i0>=nb_points || i1>=nb_points || i2>=nb_points) {
            if (error_message) cimg_sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
                                            "triangle primitive [%u]",
                                            nb_points,nb_primitives,i0,i1,i2,p);
            return false;
          }
        } break;
        case 4 : case 12 : { // Quadrangle.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++)),
            i2 = cimg::float2uint((float)*(ptrs++)),
            i3 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==12) ptrs+=8;
          if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) {
            if (error_message) cimg_sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
                                            "quadrangle primitive [%u]",
                                            nb_points,nb_primitives,i0,i1,i2,i3,p);
            return false;
          }
        } break;
        default :
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u",
                                          nb_points,nb_primitives,p,nb_inds);
          return false;
        }
        if (ptrs>ptre) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], "
                                          "%u values missing",
                                          nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre));
          return false;
        }
      }

      // Check consistency of color data.
      if (ptrs==ptre) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d (%u,%u) defines no color/texture data",
                                        nb_points,nb_primitives);
        return false;
      }
      for (unsigned int c = 0; c<nb_primitives; ++c) {
        if (*(ptrs++)!=(T)-128) ptrs+=2;
        else if ((ptrs+=3)<ptre) {
          const unsigned int
            w = (unsigned int)*(ptrs - 3),
            h = (unsigned int)*(ptrs - 2),
            s = (unsigned int)*(ptrs - 1);
          if (!h && !s) {
            if (w>=c) {
              if (error_message) cimg_sprintf(error_message,
                                              "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u "
                                              "for primitive [%u]",
                                              nb_points,nb_primitives,w,c);
              return false;
            }
          } else ptrs+=w*h*s;
        }
        if (ptrs>ptre) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], "
                                          "%u values missing",
                                          nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre));
          return false;
        }
      }

      // Check consistency of opacity data.
      if (ptrs==ptre) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d (%u,%u) defines no opacity data",
                                        nb_points,nb_primitives);
        return false;
      }
      for (unsigned int o = 0; o<nb_primitives; ++o) {
        if (*(ptrs++)==(T)-128 && (ptrs+=3)<ptre) {
          const unsigned int
            w = (unsigned int)*(ptrs - 3),
            h = (unsigned int)*(ptrs - 2),
            s = (unsigned int)*(ptrs - 1);
          if (!h && !s) {
            if (w>=o) {
              if (error_message) cimg_sprintf(error_message,
                                              "CImg3d (%u,%u) refers to invalid shared opacity indice %u "
                                              "for primitive [%u]",
                                              nb_points,nb_primitives,w,o);
              return false;
            }
          } else ptrs+=w*h*s;
        }
        if (ptrs>ptre) {
          if (error_message) cimg_sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]",
                                          nb_points,nb_primitives,o);
          return false;
        }
      }

      // Check end of data.
      if (ptrs<ptre) {
        if (error_message) cimg_sprintf(error_message,
                                        "CImg3d (%u,%u) contains %u value%s more than expected",
                                        nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
        return false;
      }
      return true;

Project: CImg
File: CImg.h

    inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) {
      static unsigned int mode = 2;
      if (is_set)  { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); }
      return mode;
    }

Project: CImg
File: CImg.h

    //! Return <tt>1 + log_10(x)</tt> of a value \c x.
    inline int xln(const int x) {
      return x>0?(int)(1 + std::log10((double)x)):1;

Project: CImg
File: CImg.h

    /**
       \param is_compressed tells if zlib compression must be used for serialization
       (this requires 'cimg_use_zlib' been enabled).
    **/
    CImg<ucharT> get_serialize(const bool is_compressed=false) const {
#ifndef cimg_use_zlib
      if (is_compressed)
        cimg::warn(_cimglist_instance
                   "get_serialize(): Unable to compress data unless zlib is enabled, "
                   "storing them uncompressed.",
                   cimglist_instance);
#endif
      CImgList<ucharT> stream;
      CImg<charT> tmpstr(128);
      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
      if (std::strstr(ptype,"unsigned")==ptype)
        cimg_snprintf(tmpstr,tmpstr._width,"%u unsigned_%s %s_endian\n",_width,ptype + 9,etype);
      else
        cimg_snprintf(tmpstr,tmpstr._width,"%u %s %s_endian\n",_width,ptype,etype);
      CImg<ucharT>::string(tmpstr,false).move_to(stream);
      cimglist_for(*this,l) {
        const CImg<T>& img = _data[l];
        cimg_snprintf(tmpstr,tmpstr._width,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum);
        CImg<ucharT>::string(tmpstr,false).move_to(stream);
        if (img._data) {
          CImg<T> tmp;
          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); }
          const CImg<T>& ref = cimg::endianness()?tmp:img;
          bool failed_to_compress = true;
          if (is_compressed) {
#ifdef cimg_use_zlib
            const ulongT siz = sizeof(T)*ref.size();
            uLongf csiz = (ulongT)compressBound(siz);
            Bytef *const cbuf = new Bytef[csiz];
            if (compress(cbuf,&csiz,(Bytef*)ref._data,siz))
              cimg::warn(_cimglist_instance
                         "get_serialize(): Failed to save compressed data, saving them uncompressed.",
                         cimglist_instance);
            else {
              cimg_snprintf(tmpstr,tmpstr._width," #%lu\n",csiz);
              CImg<ucharT>::string(tmpstr,false).move_to(stream);
              CImg<ucharT>(cbuf,csiz).move_to(stream);
              delete[] cbuf;
              failed_to_compress = false;
            }
#endif
          }
          if (failed_to_compress) { // Write in a non-compressed way.
            CImg<charT>::string("\n",false).move_to(stream);
            stream.insert(1);
            stream.back().assign((unsigned char*)ref._data,ref.size()*sizeof(T),1,1,1,true);
          }
        } else CImg<charT>::string("\n",false).move_to(stream);

Project: CImg
File: CImg.h

    //! Convert pixel values from RGB to YCbCr color spaces.
    CImg<T>& RGBtoYCbCr() {
      if (_spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "RGBtoYCbCr(): 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 ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=512))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          R = (Tfloat)p1[N],
          G = (Tfloat)p2[N],
          B = (Tfloat)p3[N],
          Y = (66*R + 129*G + 25*B + 128)/256 + 16,
          Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
          Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
        p1[N] = (T)cimg::cut(Y,0,255),
        p2[N] = (T)cimg::cut(Cb,0,255),
        p3[N] = (T)cimg::cut(Cr,0,255);
      }
      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()>=32))
      cimg_rof(*this,ptr,T) {
        const Tfloat
          val = (Tfloat)*ptr/255,
          sval = (Tfloat)(val<=0.0031308f?val*12.92f:1.055f*std::pow(val,0.416667f) - 0.055f);
        *ptr = (T)cimg::cut(sval*255,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

    **/
    const CImg<T>& save_exr(const char *const filename) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_exr(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_exr(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename);

#ifndef cimg_use_openexr
      return save_other(filename);
#else
      Imf::Rgba *const ptrd0 = new Imf::Rgba[(size_t)_width*_height], *ptrd = ptrd0, rgba;
      switch (_spectrum) {
      case 1 : { // Grayscale image.
        for (const T *ptr_r = data(), *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {
          rgba.r = rgba.g = rgba.b = (half)(*(ptr_r++));
          rgba.a = (half)1;
          *(ptrd++) = rgba;
        }
      } break;
      case 2 : { // RG image.
        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1),
               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e; ) {
          rgba.r = (half)(*(ptr_r++));
          rgba.g = (half)(*(ptr_g++));
          rgba.b = (half)0;
          rgba.a = (half)1;
          *(ptrd++) = rgba;
        }
      } break;
      case 3 : { // RGB image.
        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2),
               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {
          rgba.r = (half)(*(ptr_r++));
          rgba.g = (half)(*(ptr_g++));
          rgba.b = (half)(*(ptr_b++));
          rgba.a = (half)1;
          *(ptrd++) = rgba;
        }
      } break;
      default : { // RGBA image.
        for (const T *ptr_r = data(), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3),
               *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {
          rgba.r = (half)(*(ptr_r++));
          rgba.g = (half)(*(ptr_g++));
          rgba.b = (half)(*(ptr_b++));
          rgba.a = (half)(*(ptr_a++));
          *(ptrd++) = rgba;
        }
      } break;
      }
      Imf::RgbaOutputFile outFile(filename,_width,_height,
                                  _spectrum==1?Imf::WRITE_Y:_spectrum==2?Imf::WRITE_YA:_spectrum==3?
                                  Imf::WRITE_RGB:Imf::WRITE_RGBA);
      outFile.setFrameBuffer(ptrd0,1,_width);
      outFile.writePixels(_height);
      delete[] ptrd0;
      return *this;
#endif

Project: CImg
File: CImg.h

    **/
    bool operator==(const char *const expression) const {
      return *this==(+*this)._fill(expression,true,true,0,0,"operator==",this);

Project: CImg
File: CImg.h

    //! Compute the sinc of each pixel value \newinstance.
    CImg<Tfloat> get_sinc() const {
      return CImg<Tfloat>(*this,false).sinc();

Project: CImg
File: CImg.h


    static void _distance_scan(const unsigned int len,
                               const longT *const g,
                               longT (*const sep)(const longT, const longT, const longT *const),
                               longT (*const f)(const longT, const longT, const longT *const),
                               longT *const s,
                               longT *const t,
                               longT *const dt) {
      longT q = s[0] = t[0] = 0;
      for (int u = 1; u<(int)len; ++u) { // Forward scan.
        while ((q>=0) && f(t[q],s[q],g)>f(t[q],u,g)) { --q; }
        if (q<0) { q = 0; s[0] = u; }
        else { const longT w = 1 + sep(s[q], u, g); if (w<(longT)len) { ++q; s[q] = u; t[q] = w; }}
      }
      for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan.

Project: CImg
File: CImg.h


    void _paint(const bool wait_expose=true) {
      if (_is_closed || !_image) return;
      Display *const dpy = cimg::X11_attr().display;
      if (wait_expose) { // Send an expose event sticked to display window to force repaint.
        XEvent event;
        event.xexpose.type = Expose;
        event.xexpose.serial = 0;
        event.xexpose.send_event = 1;
        event.xexpose.display = dpy;
        event.xexpose.window = _window;
        event.xexpose.x = 0;
        event.xexpose.y = 0;
        event.xexpose.width = width();
        event.xexpose.height = height();
        event.xexpose.count = 0;
        XSendEvent(dpy,_window,0,0,&event);
      } else { // Repaint directly (may be called from the expose event).
        GC gc = DefaultGC(dpy,DefaultScreen(dpy));
#ifdef cimg_use_xshm
        if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1);
        else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#else
        XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#endif
      }

Project: CImg
File: CImg.h

    **/
    CImg<T>& rotate(const float angle, const unsigned int interpolation=1,
                    const unsigned int boundary_conditions=0) {
      const float nangle = cimg::mod(angle,360.0f);
      if (nangle==0.0f) return *this;
      return get_rotate(nangle,interpolation,boundary_conditions).move_to(*this);

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Compute Haar multiscale wavelet transform \newinstance.
    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
      if (is_empty() || !nb_scales) return +*this;
      CImg<Tfloat> res;
      const Tfloat sqrt2 = std::sqrt(2.0f);
      if (nb_scales==1) {
        switch (cimg::lowercase(axis)) { // Single scale transform
        case 'x' : {
          const unsigned int w = _width/2;
          if (w) {
            if ((w%2) && w!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image width %u is not even.",
                                          cimg_instance,
                                          w);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(xw,y,z,c);
                res(x2++,y,z,c) = (val0 - val1)/sqrt2;
                res(x2++,y,z,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forYZC(*this,y,z,c) { // Direct transform along X
              for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,c), val1 = (Tfloat)(*this)(x2++,y,z,c);
                res(x,y,z,c) = (val0 + val1)/sqrt2;
                res(xw,y,z,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        case 'y' : {
          const unsigned int h = _height/2;
          if (h) {
            if ((h%2) && h!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image height %u is not even.",
                                          cimg_instance,
                                          h);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forXZC(*this,x,z,c) { // Inverse transform along Y
              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,yh,z,c);
                res(x,y2++,z,c) = (val0 - val1)/sqrt2;
                res(x,y2++,z,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forXZC(*this,x,z,c) {
              for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { // Direct transform along Y
                const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,c), val1 = (Tfloat)(*this)(x,y2++,z,c);
                res(x,y,z,c)  = (val0 + val1)/sqrt2;
                res(x,yh,z,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        case 'z' : {
          const unsigned int d = _depth/2;
          if (d) {
            if ((d%2) && d!=1)
              throw CImgInstanceException(_cimg_instance
                                          "haar(): Sub-image depth %u is not even.",
                                          cimg_instance,
                                          d);

            res.assign(_width,_height,_depth,_spectrum);
            if (invert) cimg_forXYC(*this,x,y,c) { // Inverse transform along Z
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) {
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,c), val1 = (Tfloat)(*this)(x,y,zd,c);
                res(x,y,z2++,c) = (val0 - val1)/sqrt2;
                res(x,y,z2++,c) = (val0 + val1)/sqrt2;
              }
            } else cimg_forXYC(*this,x,y,c) {
              for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z
                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,c), val1 = (Tfloat)(*this)(x,y,z2++,c);
                res(x,y,z,c)  = (val0 + val1)/sqrt2;
                res(x,y,zd,c) = (val1 - val0)/sqrt2;
              }
            }
          } else return *this;
        } break;
        default :
          throw CImgArgumentException(_cimg_instance
                                      "haar(): Invalid specified axis '%c' "
                                      "(should be { x | y | z }).",
                                      cimg_instance,
                                      axis);
        }
      } else { // Multi-scale version
        if (invert) {
          res.assign(*this,false);
          switch (cimg::lowercase(axis)) {
          case 'x' : {
            unsigned int w = _width;
            for (unsigned int s = 1; w && s<nb_scales; ++s) w/=2;
            for (w = w?w:1; w<=_width; w*=2) res.draw_image(res.get_crop(0,w - 1).get_haar('x',true,1));
          } break;
          case 'y' : {
            unsigned int h = _width;
            for (unsigned int s = 1; h && s<nb_scales; ++s) h/=2;
            for (h = h?h:1; h<=_height; h*=2) res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',true,1));
          } break;
          case 'z' : {
            unsigned int d = _depth;
            for (unsigned int s = 1; d && s<nb_scales; ++s) d/=2;
            for (d = d?d:1; d<=_depth; d*=2)
              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',true,1));
          } break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "haar(): Invalid specified axis '%c' "
                                        "(should be { x | y | z }).",
                                        cimg_instance,
                                        axis);
          }
        } else { // Direct transform
          res = get_haar(axis,false,1);
          switch (cimg::lowercase(axis)) {
          case 'x' : {
            for (unsigned int s = 1, w = _width/2; w && s<nb_scales; ++s, w/=2)
              res.draw_image(res.get_crop(0,w - 1).get_haar('x',false,1));
          } break;
          case 'y' : {
            for (unsigned int s = 1, h = _height/2; h && s<nb_scales; ++s, h/=2)
              res.draw_image(res.get_crop(0,0,_width - 1,h - 1).get_haar('y',false,1));
          } break;
          case 'z' : {
            for (unsigned int s = 1, d = _depth/2; d && s<nb_scales; ++s, d/=2)
              res.draw_image(res.get_crop(0,0,0,_width - 1,_height - 1,d - 1).get_haar('z',false,1));
          } break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "haar(): Invalid specified axis '%c' "
                                        "(should be { x | y | z }).",
                                        cimg_instance,
                                        axis);
          }
        }
      }
      return res;

Project: CImg
File: CImg.h

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

Project: CImg
File: CImg.h

    //! Test if list contains image with specified indice.
    /**
       \param n Index of the checked image.
    **/

Project: CImg
File: CImg.h


      static double mp_factorial(_cimg_math_parser& mp) {
        return cimg::factorial(_mp_arg(2));

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::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

    **/
    inline void info() {
      std::fprintf(cimg::output(),"\n %s%sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags:\n\n",
                   cimg::t_red,cimg::t_bold,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
                   cimg::t_normal,cimg_date,cimg_time);

      std::fprintf(cimg::output(),"  > Operating System:       %s%-13s%s %s('cimg_OS'=%d)%s\n",
                   cimg::t_bold,
                   cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
                   cimg::t_normal,cimg::t_green,
                   cimg_OS,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > CPU endianness:         %s%s Endian%s\n",
                   cimg::t_bold,
                   cimg::endianness()?"Big":"Little",
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Verbosity mode:         %s%-13s%s %s('cimg_verbosity'=%d)%s\n",
                   cimg::t_bold,
                   cimg_verbosity==0?"Quiet":
                   cimg_verbosity==1?"Console":
                   cimg_verbosity==2?"Dialog":
                   cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings",
                   cimg::t_normal,cimg::t_green,
                   cimg_verbosity,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Stricts warnings:       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_strict_warnings
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Support for C++11:      %s%-13s%s %s('cimg_use_cpp11'=%d)%s\n",
                   cimg::t_bold,
                   cimg_use_cpp11?"Yes":"No",
                   cimg::t_normal,cimg::t_green,
                   (int)cimg_use_cpp11,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using VT100 messages:   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_vt100
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Display type:           %s%-13s%s %s('cimg_display'=%d)%s\n",
                   cimg::t_bold,
                   cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown",
                   cimg::t_normal,cimg::t_green,
                   (int)cimg_display,
                   cimg::t_normal);

#if cimg_display==1
      std::fprintf(cimg::output(),"  > Using XShm for X11:     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_xshm
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using XRand for X11:    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_xrandr
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
#endif
      std::fprintf(cimg::output(),"  > Using OpenMP:           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_openmp
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
      std::fprintf(cimg::output(),"  > Using PNG library:      %s%-13s%s %s('cimg_use_png' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_png
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
      std::fprintf(cimg::output(),"  > Using JPEG library:     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_jpeg
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using TIFF library:     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_tiff
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using Magick++ library: %s%-13s%s %s('cimg_use_magick' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_magick
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using FFTW3 library:    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_fftw3
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using LAPACK library:   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_lapack
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      char *const tmp = new char[1024];
      cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::imagemagick_path());
      std::fprintf(cimg::output(),"  > Path of ImageMagick:    %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::graphicsmagick_path());
      std::fprintf(cimg::output(),"  > Path of GraphicsMagick: %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::medcon_path());
      std::fprintf(cimg::output(),"  > Path of 'medcon':       %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::temporary_path());
      std::fprintf(cimg::output(),"  > Temporary path:         %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"\n");
      delete[] tmp;

Project: CImg
File: CImg.h


    void _set_colormap(Colormap& _colormap, const unsigned int dim) {
      XColor *const colormap = new XColor[256];
      switch (dim) {
      case 1 : { // colormap for greyscale images
        for (unsigned int index = 0; index<256; ++index) {
          colormap[index].pixel = index;
          colormap[index].red = colormap[index].green = colormap[index].blue = (unsigned short)(index<<8);
          colormap[index].flags = DoRed | DoGreen | DoBlue;
        }
      } break;
      case 2 : { // colormap for RG images
        for (unsigned int index = 0, r = 8; r<256; r+=16)
          for (unsigned int g = 8; g<256; g+=16) {
            colormap[index].pixel = index;
            colormap[index].red = colormap[index].blue = (unsigned short)(r<<8);
            colormap[index].green = (unsigned short)(g<<8);
            colormap[index++].flags = DoRed | DoGreen | DoBlue;
          }
      } break;
      default : { // colormap for RGB images
        for (unsigned int index = 0, r = 16; r<256; r+=32)
          for (unsigned int g = 16; g<256; g+=32)
            for (unsigned int b = 32; b<256; b+=64) {
              colormap[index].pixel = index;
              colormap[index].red = (unsigned short)(r<<8);
              colormap[index].green = (unsigned short)(g<<8);
              colormap[index].blue = (unsigned short)(b<<8);
              colormap[index++].flags = DoRed | DoGreen | DoBlue;
            }
      }
      }
      XStoreColors(cimg::X11_attr().display,_colormap,colormap,256);
      delete[] colormap;

Project: CImg
File: CImg.h

  template<typename T>
  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
    return instance.get_asin();

Project: CImg
File: CImg.h

    template<typename tc>
    CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
                         const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
                         const tc *const color, const float opacity=1,
                         const float precision=4, const unsigned int pattern=~0U,
                         const bool init_hatch=true) {
      if (is_empty()) return *this;
      if (!color)
        throw CImgArgumentException(_cimg_instance
                                    "draw_spline(): Specified color is (null).",
                                    cimg_instance);
      if (x0==x1 && y0==y1 && z0==z1) return draw_point(x0,y0,z0,color,opacity);
      bool ninit_hatch = init_hatch;
      const float
        ax = u0 + u1 + 2*(x0 - x1),
        bx = 3*(x1 - x0) - 2*u0 - u1,
        ay = v0 + v1 + 2*(y0 - y1),
        by = 3*(y1 - y0) - 2*v0 - v1,
        az = w0 + w1 + 2*(z0 - z1),
        bz = 3*(z1 - z0) - 2*w0 - w1,
        _precision = 1/(cimg::hypot((float)x0 - x1,(float)y0 - y1)*(precision>0?precision:1));
      int ox = x0, oy = y0, oz = z0;
      for (float t = 0; t<1; t+=_precision) {
        const float t2 = t*t, t3 = t2*t;
        const int
          nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
          ny = (int)(ay*t3 + by*t2 + v0*t + y0),
          nz = (int)(az*t3 + bz*t2 + w0*t + z0);
        draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
        ninit_hatch = false;
        ox = nx; oy = ny; oz = nz;
      }
      return draw_line(ox,oy,oz,x1,y1,z1,color,opacity,pattern,false);

Project: CImg
File: CImg.h

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

      T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
      const ulongT whd = (ulongT)_width*_height*_depth;
      cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=512))
      for (ulongT N = 0; N<whd; ++N) {
        const Tfloat
          Y = (Tfloat)p1[N] - 16,
          Cb = (Tfloat)p2[N] - 128,
          Cr = (Tfloat)p3[N] - 128,
          R = (298*Y + 409*Cr + 128)/256,
          G = (298*Y - 100*Cb - 208*Cr + 128)/256,
          B = (298*Y + 516*Cb + 128)/256;
        p1[N] = (T)cimg::cut(R,0,255),
        p2[N] = (T)cimg::cut(G,0,255),
        p3[N] = (T)cimg::cut(B,0,255);
      }
      return *this;

Project: CImg
File: CImg.h

    template<typename t>
    CImg<T>& operator+=(const t value) {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=524288))
      cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value);
      return *this;

Project: CImg
File: CImg.h

    **/
    inline bool is_file(const char *const path) {
      if (!path || !*path) return false;
      std::FILE *const file = std_fopen(path,"rb");
      if (!file) return false;
      std::fclose(file);
      return !is_directory(path);

Project: CImg
File: CImg.h

    **/
    CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
      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);
      if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
      if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
      if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
      return *this;

Project: CImg
File: CImg.h


    const CImg<T>& _save_png(std::FILE *const file, const char *const filename,
                             const unsigned int bytes_per_pixel=0) const {
      if (!file && !filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_png(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(file,filename); return *this; }

#ifndef cimg_use_png
      cimg::unused(bytes_per_pixel);
      if (!file) return save_other(filename);
      else throw CImgIOException(_cimg_instance
                                 "save_png(): Unable to save data in '(*FILE)' unless libpng is enabled.",
                                 cimg_instance);
#else

#if defined __GNUC__
      const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning.
      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
      volatile double stmin, stmax = (double)max_min(stmin);
#else
      const char *nfilename = filename;
      std::FILE *nfile = file?file:cimg::fopen(nfilename,"wb");
      double stmin, stmax = (double)max_min(stmin);
#endif

      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_png(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename);

      if (_spectrum>4)
        cimg::warn(_cimg_instance
                   "save_png(): Instance is multispectral, only the three first channels will be saved in file '%s'.",
                   cimg_instance,
                   filename);

      if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
        cimg::warn(_cimg_instance
                   "save_png(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.",
                   cimg_instance,
                   filename,stmin,stmax);

      // Setup PNG structures for write
      png_voidp user_error_ptr = 0;
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn,
                                                    user_warning_fn);
      if (!png_ptr){
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Failed to initialize 'png_ptr' structure when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_infop info_ptr = png_create_info_struct(png_ptr);
      if (!info_ptr) {
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Failed to initialize 'info_ptr' structure when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_init_io(png_ptr, nfile);

      const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8);

      int color_type;
      switch (spectrum()) {
      case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
      case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
      case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
      default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
      }
      const int interlace_type = PNG_INTERLACE_NONE;
      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
      const int filter_method = PNG_FILTER_TYPE_DEFAULT;
      png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method);
      png_write_info(png_ptr,info_ptr);
      const int byte_depth = bit_depth>>3;
      const int numChan = spectrum()>4?4:spectrum();
      const int pixel_bit_depth_flag = numChan * (bit_depth - 1);

      // Allocate Memory for Image Save and Fill pixel data
      png_bytep *const imgData = new png_byte*[_height];
      for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width];
      const T *pC0 = data(0,0,0,0);
      switch (pixel_bit_depth_flag) {
      case 7 :  { // Gray 8-bit
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
        }
      } break;
      case 14 : { // Gray w/ Alpha 8-bit
        const T *pC1 = data(0,0,0,1);
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
          }
        }
      } break;
      case 21 :  { // RGB 8-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);
        cimg_forY(*this,y) {
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
            *(ptrd++) = (unsigned char)*(pC2++);
          }
        }
      } break;
      case 28 : { // RGB x/ Alpha 8-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);
        cimg_forY(*this,y){
          unsigned char *ptrd = imgData[y];
          cimg_forX(*this,x){
            *(ptrd++) = (unsigned char)*(pC0++);
            *(ptrd++) = (unsigned char)*(pC1++);
            *(ptrd++) = (unsigned char)*(pC2++);
            *(ptrd++) = (unsigned char)*(pC3++);
          }
        }
      } break;
      case 15 : { // Gray 16-bit
        cimg_forY(*this,y){
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width);
        }
      } break;
      case 30 : { // Gray w/ Alpha 16-bit
        const T *pC1 = data(0,0,0,1);
        cimg_forY(*this,y){
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width);
        }
      } break;
      case 45 : { // RGB 16-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2);
        cimg_forY(*this,y) {
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
            *(ptrd++) = (unsigned short)*(pC2++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width);
        }
      } break;
      case 60 : { // RGB w/ Alpha 16-bit
        const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3);
        cimg_forY(*this,y) {
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
          cimg_forX(*this,x) {
            *(ptrd++) = (unsigned short)*(pC0++);
            *(ptrd++) = (unsigned short)*(pC1++);
            *(ptrd++) = (unsigned short)*(pC2++);
            *(ptrd++) = (unsigned short)*(pC3++);
          }
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width);
        }
      } break;
      default :
        if (!file) cimg::fclose(nfile);
        throw CImgIOException(_cimg_instance
                              "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.",
                              cimg_instance,
                              nfilename?nfilename:"(FILE*)");
      }
      png_write_image(png_ptr,imgData);
      png_write_end(png_ptr,info_ptr);
      png_destroy_write_struct(&png_ptr, &info_ptr);

      // Deallocate Image Write Memory
      cimg_forY(*this,n) delete[] imgData[n];
      delete[] imgData;

      if (!file) cimg::fclose(nfile);
      return *this;
#endif

Project: CImg
File: CImg.h

    template<typename tp, typename tf, typename tc, 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 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,
                           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,zbuffer);

Project: CImg
File: CImg.h

      \param[out] colors At return, contains the list of 3d object colors.
      \return List of 3d object vertices.
    **/
    template<typename tf, typename tc>

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) {
      return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type,
                           is_double_sided,focale,lightx,lighty,lightz,
                           specular_lightness,specular_shininess,CImg<floatT>::empty());

Project: CImg
File: CImg.h

    **/
    CImg<T>& atan() {
      if (is_empty()) return *this;
      cimg_pragma_openmp(parallel for cimg_openmp_if(size()>=8192))
      cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);
      return *this;

Project: CImg
File: CImg.h

    }

    //! Unserialize a CImg<unsigned char> serialized buffer into a CImgList<T> list.
    template<typename t>
    static CImgList<T> get_unserialize(const CImg<t>& buffer) {
#ifdef cimg_use_zlib
#define _cimgz_unserialize_case(Tss) { \
        Bytef *cbuf = 0; \
        if (sizeof(t)!=1 || cimg::type<t>::string()==cimg::type<bool>::string()) { \
          cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \
          for (ulongT i = 0; i<csiz; ++i) *(_cbuf++) = (Bytef)*(stream++); \
          is_bytef = false; \
        } else { cbuf = (Bytef*)stream; stream+=csiz; is_bytef = true; } \
        raw.assign(W,H,D,C); \
        uLongf destlen = raw.size()*sizeof(Tss); \
        uncompress((Bytef*)raw._data,&destlen,cbuf,csiz); \
        if (!is_bytef) delete[] cbuf; \
      }
#else
#define _cimgz_unserialize_case(Tss) \
      throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unable to unserialize compressed data " \
                                  "unless zlib is enabled.", \
                                  pixel_type());
#endif

#define _cimg_unserialize_case(Ts,Tss) \
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
        for (unsigned int l = 0; l<N; ++l) { \
          j = 0; while ((i=(int)*stream)!='\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; } \
          ++stream; tmp[j] = 0; \
          W = H = D = C = 0; csiz = 0; \
          if ((err = cimg_sscanf(tmp,"%u %u %u %u #" cimg_fuint64,&W,&H,&D,&C,&csiz))<4) \
            throw CImgArgumentException("CImgList<%s>::unserialize(): Invalid specified size (%u,%u,%u,%u) for " \
                                        "image #%u in serialized buffer.", \
                                        pixel_type(),W,H,D,C,l); \
          if (W*H*D*C>0) { \
            CImg<Tss> raw; \
            CImg<T> &img = res._data[l]; \
            if (err==5) _cimgz_unserialize_case(Tss) \
            else if (sizeof(Tss)==sizeof(t) && cimg::type<Tss>::is_float()==cimg::type<t>::is_float()) { \
              raw.assign((Tss*)stream,W,H,D,C,true); \
              stream+=raw.size(); \
            } else { \
              raw.assign(W,H,D,C); \
              CImg<ucharT> _raw((unsigned char*)raw._data,W*sizeof(Tss),H,D,C,true); \
              cimg_for(_raw,p,unsigned char) *p = (unsigned char)*(stream++); \
            } \
            if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \
            raw.move_to(img); \
          } \
        } \
        loaded = true; \
      }

      if (buffer.is_empty())
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).",
                                    pixel_type());
      CImgList<T> res;
      const t *stream = buffer._data, *const estream = buffer._data + buffer.size();
      bool loaded = false, endian = cimg::endianness(), is_bytef = false;
      CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
      *tmp = *str_pixeltype = *str_endian = 0;
      unsigned int j, N = 0, W, H, D, C;
      uint64T csiz;
      int i, err;
      cimg::unused(is_bytef);
      do {
        j = 0; while ((i=(int)*stream)!='\n' && stream<estream && j<255) { ++stream; tmp[j++] = (char)i; }
        ++stream; tmp[j] = 0;
      } while (*tmp=='#' && stream<estream);
      err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z64_]%*c%255[sA-Za-z_ ]",
                        &N,str_pixeltype._data,str_endian._data);
      if (err<2)
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): CImg header not found in serialized buffer.",
                                    pixel_type());
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
      res.assign(N);
      _cimg_unserialize_case("bool",bool);
      _cimg_unserialize_case("unsigned_char",unsigned char);
      _cimg_unserialize_case("uchar",unsigned char);
      _cimg_unserialize_case("char",char);
      _cimg_unserialize_case("unsigned_short",unsigned short);
      _cimg_unserialize_case("ushort",unsigned short);
      _cimg_unserialize_case("short",short);
      _cimg_unserialize_case("unsigned_int",unsigned int);
      _cimg_unserialize_case("uint",unsigned int);
      _cimg_unserialize_case("int",int);
      _cimg_unserialize_case("unsigned_int64",uint64T);
      _cimg_unserialize_case("uint64",uint64T);
      _cimg_unserialize_case("int64",int64T);
      _cimg_unserialize_case("float",float);
      _cimg_unserialize_case("double",double);
      if (!loaded)
        throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined "