Logo Search packages:      
Sourcecode: bbdate version File versions  Download package

Image.cc

 // Image.cc adapted for use in bbtools 03-1999 by John Kennis
//    
//
// Original notice:
//
// Image.cc for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 1999 by Brad Hughes, bhughes@tcac.net
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// (See the included file COPYING / GPL-2.0)
//

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#ifdef HAVE_CONFIG_H
#  include "../config.h"
#endif

#include "Basewindow.hh"
#include "Image.hh"

#ifdef HAVE_STDIO_H
#  include <stdio.h>
#endif

#ifdef HAVE_MALLOC_H
#  include <malloc.h>
#else
#  ifdef STDC_HEADERS
#    include <stdlib.h>
#  endif
#endif


BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) {
  control = c;

  width = ((signed) w > 0) ? w : 1;
  height = ((signed) h > 0) ? h : 1;

  red = new unsigned char[width * height];
  green = new unsigned char[width * height];
  blue = new unsigned char[width * height];

  cpc = control->getColorsPerChannel();
  cpccpc = cpc * cpc;
  
  control->getMaskTables(&tr, &tg, &tb, &roff, &goff, &boff);
  
  if (control->getVisual()->c_class != TrueColor)
    control->getColorTable(&colors, &ncolors);
}


BImage::~BImage(void) {
  if (red) delete [] red;
  if (green) delete [] green;
  if (blue) delete [] blue;
}


Pixmap BImage::render(const BTexture *texture)
{
  if (texture->texture & BImage_Solid) {
    return render_solid(texture);
  } else if (texture->texture & BImage_Gradient)
    return render_gradient(texture);
  
  return None;
}


Pixmap BImage::render_solid(const BTexture *texture) {
  Pixmap pixmap = XCreatePixmap(control->getDisplay(),
                        control->getDrawable(), width,
                        height, control->getDepth());
  if (pixmap == None) {
    fprintf(stderr, "BImage::render_solid: error creating pixmap\n");
    return None;
  }
  
  XGCValues gcv;
  GC gc, hgc, lgc;
  
  gcv.foreground = texture->color.pixel;
  gcv.fill_style = FillSolid;
  gc = XCreateGC(control->getDisplay(), pixmap, GCForeground | GCFillStyle,
             &gcv);
  
  gcv.foreground = texture->hiColor.pixel;
  hgc = XCreateGC(control->getDisplay(), pixmap, GCForeground, &gcv);
  
  gcv.foreground = texture->loColor.pixel;
  lgc = XCreateGC(control->getDisplay(), pixmap, GCForeground, &gcv);
  
  XFillRectangle(control->getDisplay(), pixmap, gc, 0, 0, width, height);
  
  if (texture->texture & BImage_Bevel1) {
    if (texture->texture & BImage_Raised) {
      XDrawLine(control->getDisplay(), pixmap, lgc, 0, height - 1,
            width - 1, height - 1);
      XDrawLine(control->getDisplay(), pixmap, lgc, width - 1, height - 1,
            width - 1, 0);
      
      XDrawLine(control->getDisplay(), pixmap, hgc, 0, 0,
            width - 1, 0);
      XDrawLine(control->getDisplay(), pixmap, hgc, 0, height - 1,
            0, 0);
    } else if (texture->texture & BImage_Sunken) {
      XDrawLine(control->getDisplay(), pixmap, hgc, 0, height - 1,
            width - 1, height - 1);
      XDrawLine(control->getDisplay(), pixmap, hgc, width - 1, height - 1,
            width - 1, 0);
      
      XDrawLine(control->getDisplay(), pixmap, lgc, 0, 0, width - 1, 0);
      XDrawLine(control->getDisplay(), pixmap, lgc, 0, height - 1, 0, 0);
    }
  } else if (texture->texture & BImage_Bevel2) {
    if (texture->texture & BImage_Raised) {
      XDrawLine(control->getDisplay(), pixmap, lgc, 1, height - 3,
            width - 3, height - 3);
      XDrawLine(control->getDisplay(), pixmap, lgc, width - 3, height - 3,
            width - 3, 1);
      
      XDrawLine(control->getDisplay(), pixmap, hgc, 1, 1,
            width - 3, 1);
      XDrawLine(control->getDisplay(), pixmap, hgc, 1, height - 3,
            1, 1);
    } else if (texture->texture & BImage_Sunken) {
      XDrawLine(control->getDisplay(), pixmap, hgc, 1, height - 3,
            width - 3, height - 3);
      XDrawLine(control->getDisplay(), pixmap, hgc, width - 3, height - 3,
            width - 3, 1);
      
      XDrawLine(control->getDisplay(), pixmap, lgc, 1, 1, width - 3, 1);
      XDrawLine(control->getDisplay(), pixmap, lgc, 1, height - 3, 1, 1);
    }
  }
  
  XFreeGC(control->getDisplay(), gc);
  XFreeGC(control->getDisplay(), hgc);
  XFreeGC(control->getDisplay(), lgc);
  
  return pixmap;
}


Pixmap BImage::render_gradient(const BTexture *texture) {
  int inverted = 0;
  
  if (texture->texture & BImage_Sunken) {
    from = texture->colorTo;
    to = texture->color;

    if (! (texture->texture & BImage_Invert)) inverted = 1;
  } else {
    from = texture->color;
    to = texture->colorTo;
    
    if (texture>texture & BImage_Invert) inverted = 1;
  }
  
  if (texture->texture & BImage_Diagonal) dgradient();
  else if (texture->texture & BImage_Horizontal) hgradient();
  else if (texture->texture & BImage_Vertical) vgradient();

  if (texture->texture & BImage_Bevel1) bevel1();
  else if (texture->texture & BImage_Bevel2) bevel2();
  
  if (inverted) invert();
  
  return renderPixmap();
}


XImage *BImage::renderXImage(void) {
  XImage *image = XCreateImage(control->getDisplay(), control->getVisual(),
                         control->getDepth(), ZPixmap,
                         0, 0, width, height, 32, 0);
  if (! image) {
    fprintf(stderr, "BImage::renderXImage: error creating XImage\n");
    return 0;
  }

  unsigned char *d = (unsigned char *) malloc(image->bytes_per_line * height);
  if (! d) {
    fprintf(stderr,
          "BImage::renderXImage: error allocating memory for image\n");
    XDestroyImage(image);
    return 0;
  }
  
  register unsigned int x, y, r = 0, g = 0, b = 0, i, off;
  
  unsigned char *idata = d, *pd = d, *pr, *pg, *pb;
  unsigned long pixel;

  if ((! tr) || (! tg) || (! tb)) {
    fprintf(stderr, "BImage::renderXImage: error getting color mask tables\n");
    XDestroyImage(image);
    return 0;
  }
  
  if (control->getVisual()->c_class != TrueColor)
    if ((! colors) || (! ncolors)) {
      fprintf(stderr,
            "BImage::renderXImage: error getting pseudo color tables\n");
      XDestroyImage(image);
      return 0;
    }

  if (control->doDither()) {
    short er, eg, eb, *gor, *og, *ob, *gnor, *nog, *nob, *por, *pog, *pob;
    unsigned short *ort, *ogt, *obt;
    
    control->getDitherBuffers(width + 2, &gor, &og, &ob, &gnor, &nog, &nob,
                        &ort, &ogt, &obt);
    if ((! gor) || (! og) || (! ob) || (! gnor) || (! nog) || (! nob) ||
      (! ort) || (! ogt) || (! obt)) {
      fprintf(stderr,
            "BImage::renderXImage: error getting dither information\n");
      XDestroyImage(image);
      return 0;
    }
    
    x = width;

    por = gor;
    pog = og;
    pob = ob;

    pr = red;
    pg = green;
    pb = blue;

    while (x--) {
      *(por++) = *(pr++);
      *(pog++) = *(pg++);
      *(pob++) = *(pb++);
    }
    
    *por = *pog = *pob = 0;
    
    for (y = 0, off = 0; y < height; y++) {
      if (y < (height - 1)) {
      for (x = 0, i = off + width; x < width; x++, i++) {
        *(gnor + x) = *(red + i);
        *(nog + x) = *(green + i);
        *(nob + x) = *(blue + i);
      }
      
      i--;
      *(gnor + x) = *(red + i);
      *(nog + x) = *(green + i);
      *(nob + x) = *(blue + i);
      }
      
      for (x = 0; x < width; x++) {
      if (*(gor + x) > 255) *(gor + x) = 255;
      else if (*(gor + x) < 0) *(gor + x) = 0;
      if (*(og + x) > 255) *(og + x) = 255;
      else if (*(og + x) < 0) *(og + x) = 0;
      if (*(ob + x) > 255) *(ob + x) = 255;
      else if (*(ob + x) < 0) *(ob + x) = 0;
      
      r = *(tr + *(gor + x));
      g = *(tg + *(og + x));
      b = *(tb + *(ob + x));
      
      switch (control->getVisual()->c_class) {
      case StaticColor:
      case PseudoColor:
        pixel = (r * cpccpc) + (g * cpc) + b;
        *idata++ = colors[pixel].pixel;
        
        break;
        
      case TrueColor:
        pixel = (r << roff) | (g << goff) | (b << boff);
        
        switch (image->byte_order) {
        case MSBFirst:
          {
            switch (image->bits_per_pixel) {
            case 32: *(idata++) = (pixel >> 24);
            case 24: *(idata++) = (pixel >> 16);
            case 16: *(idata++) = (pixel >> 8);
            default: *(idata++) = (pixel);
            }

            break;
          }

        case LSBFirst:
          {
            *(idata++) = pixel;
            
            switch (image->bits_per_pixel) {
            case 32:
            *(idata++) = (pixel >> 8);
            *(idata++) = (pixel >> 16);
            *(idata++) = (pixel >> 24);
            break;

            case 24:
            *(idata++) = (pixel >> 8);
            *(idata++) = (pixel >> 16);
            break;
            
            case 16:
            *(idata++) = (pixel >> 8);
            break;
            }

            break;
          }
        }
        
          break;
        
      default:
        fprintf(stderr, "BImage::renderXImage: unsupported visual\n");
        image->data = (char *) d;
        XDestroyImage(image);
        return 0;
      }

      er = *(gor + x) - *(ort + *(gor + x));
      eg = *(og + x) - *(ogt + *(og + x));
      eb = *(ob + x) - *(obt + *(ob + x));
      
      *(gor + x + 1) += er;
      *(og + x + 1) += eg;
      *(ob + x + 1) += eb;
      
      *(gnor + x) += er;
      *(nog + x) += eg;
      *(nob + x) += eb;
      
      *(gnor + x + 1) -= (er >> 1) + (er >> 2);
      *(nog + x + 1) -= (eg >> 1) + (eg >> 2);
      *(nob + x + 1) -= (eb >> 1) + (eb >> 2);
      }
      
      off += image->width;
      idata = (pd += image->bytes_per_line);
      
      por = gor; gor = gnor; gnor = por;
      pog = og; og = nog; nog = pog;
      pob = ob; ob = nob; nob = pob;
    }
  } else {
    for (y = 0, off = 0; y < height; y++) {
      for (x = 0; x < width; x++, off++) {
      r = *(tr + *(red + off));
      g = *(tg + *(green + off));
      b = *(tb + *(blue + off));
      
      switch (control->getVisual()->c_class) {
      case StaticColor:
      case PseudoColor:
        pixel = (r * cpccpc) + (g * cpc) + b;
        *idata++ = colors[pixel].pixel;
        break;
        
      case TrueColor:
        pixel = (r << roff) | (g << goff) | (b << boff);
        
        switch (image->byte_order) {
        case MSBFirst:
          {
            switch (image->bits_per_pixel) {
            case 32: *(idata++) = (pixel >> 24);
            case 24: *(idata++) = (pixel >> 16);
            case 16: *(idata++) = (pixel >> 8);
            default: *(idata++) = (pixel);
            }
            
            break;
          }
          
        case LSBFirst:
          {
            *(idata++) = pixel;
            
            switch (image->bits_per_pixel) {
            case 32:
            *(idata++) = (pixel >> 8);
            *(idata++) = (pixel >> 16);
            *(idata++) = (pixel >> 24);
            break;
            
            case 24:
            *(idata++) = (pixel >> 8);
            *(idata++) = (pixel >> 16);
            break;
            
            case 16:
            *(idata++) = (pixel >> 8);
            break;
            }
            
            break;
          }
        }
        
        break;
        
      default:
        fprintf(stderr, "BImage::renderXImage: unsupported visual\n");
        image->data = (char *) d;
        XDestroyImage(image);
        return 0; 
      }
      }

      idata = (pd += image->bytes_per_line);
    }
  }
  
  image->data = (char *) d;
  return image;
}


Pixmap BImage::renderPixmap(void) {
  Pixmap pixmap = XCreatePixmap(control->getDisplay(),
                        control->getDrawable(), width,
                                height, control->getDepth());
  if (pixmap == None) {
    fprintf(stderr, "BImage::renderPixmap: error creating pixmap\n");
    return None;
  }

  XImage *image = renderXImage();
  if (! image) {
    XFreePixmap(control->getDisplay(), pixmap);
    return None;
  }
  
  XPutImage(control->getDisplay(), pixmap,
          DefaultGC(control->getDisplay(),
                  control->getScreenNumber()),
            image, 0, 0, 0, 0, width, height);
  XDestroyImage(image);
  return pixmap;
}


void BImage::bevel1(void) {
  if (width > 2 && height > 2) {
    unsigned char *pr = red, *pg = green, *pb = blue;
    
    register unsigned char r, g, b, rr ,gg ,bb;
    register unsigned int w = width, h = height - 1, wh = w * h;
    
    while (--w) {
      r = *pr;
      rr = r + (r >> 1);
      if (rr < r) rr = ~0;
      g = *pg;
      gg = g + (g >> 1);
      if (gg < g) gg = ~0;
      b = *pb;
      bb = b + (b >> 1);
      if (bb < b) bb = ~0;
      
      *pr = rr;
      *pg = gg;
      *pb = bb;
      
      r = *(pr + wh);
      rr = (r >> 2) + (r >> 1);
      if (rr > r) rr = 0;
      g = *(pg + wh);
      gg = (g >> 2) + (g >> 1);
      if (gg > g) gg = 0;
      b = *(pb + wh);
      bb = (b >> 2) + (b >> 1);
      if (bb > b) bb = 0;
      
      *((pr++) + wh) = rr;
      *((pg++) + wh) = gg;
      *((pb++) + wh) = bb;
    }
    
    r = *pr;
    rr = r + (r >> 1);
    if (rr < r) rr = ~0;
    g = *pg;
    gg = g + (g >> 1); 
    if (gg < g) gg = ~0;
    b = *pb;
    bb = b + (b >> 1);
    if (bb < b) bb = ~0;
    
    *pr = rr;
    *pg = gg;
    *pb = bb;
    
    r = *(pr + wh);
    rr = (r >> 2) + (r >> 1);
    if (rr > r) rr = 0;
    g = *(pg + wh);
    gg = (g >> 2) + (g >> 1);
    if (gg > g) gg = 0;
    b = *(pb + wh);
    bb = (b >> 2) + (b >> 1);
    if (bb > b) bb = 0;
    
    *(pr + wh) = rr;
    *(pg + wh) = gg;
    *(pb + wh) = bb;
    
    pr = red + width;
    pg = green + width;
    pb = blue + width;
    
    while (--h) {
      r = *pr;
      rr = r + (r >> 1);
      if (rr < r) rr = ~0;
      g = *pg;
      gg = g + (g >> 1);
      if (gg < g) gg = ~0;
      b = *pb;
      bb = b + (b >> 1);
      if (bb < b) bb = ~0;
      
      *pr = rr;
      *pg = gg;
      *pb = bb;
      
      pr += width - 1;
      pg += width - 1;
      pb += width - 1;
      
      r = *pr;
      rr = (r >> 2) + (r >> 1);
      if (rr > r) rr = 0;
      g = *pg;
      gg = (g >> 2) + (g >> 1);
      if (gg > g) gg = 0;
      b = *pb;
      bb = (b >> 2) + (b >> 1);
      if (bb > b) bb = 0;
      
      *(pr++) = rr;
      *(pg++) = gg;
      *(pb++) = bb;
    }
    
    r = *pr;
    rr = r + (r >> 1);
    if (rr < r) rr = ~0;
    g = *pg;
    gg = g + (g >> 1);
    if (gg < g) gg = ~0;
    b = *pb;
    bb = b + (b >> 1);
    if (bb < b) bb = ~0;
    
    *pr = rr;
    *pg = gg;
    *pb = bb;
    
    pr += width - 1;
    pg += width - 1;
    pb += width - 1;
    
    r = *pr;
    rr = (r >> 2) + (r >> 1);
    if (rr > r) rr = 0;
    g = *pg;
    gg = (g >> 2) + (g >> 1);
    if (gg > g) gg = 0;
    b = *pb;
    bb = (b >> 2) + (b >> 1);
    if (bb > b) bb = 0;
    
    *pr = rr;
    *pg = gg;
    *pb = bb;
  }
}


void BImage::bevel2(void) {
  if (width > 4 && height > 4) {
    unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
      *pg = green + width + 1, *pb = blue + width + 1;
    unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
    
    while (--w) {
      r = *pr;
      rr = r + (r >> 1);
      if (rr < r) rr = ~0;
      g = *pg;
      gg = g + (g >> 1);
      if (gg < g) gg = ~0;
      b = *pb;
      bb = b + (b >> 1);
      if (bb < b) bb = ~0;
      
      *pr = rr;
      *pg = gg;
      *pb = bb;
      
      r = *(pr + wh);
      rr = (r >> 2) + (r >> 1);
      if (rr > r) rr = 0;
      g = *(pg + wh);
      gg = (g >> 2) + (g >> 1);
      if (gg > g) gg = 0;
      b = *(pb + wh);
      bb = (b >> 2) + (b >> 1);
      if (bb > b) bb = 0;
      
      *((pr++) + wh) = rr;
      *((pg++) + wh) = gg;
      *((pb++) + wh) = bb;
    }
    
    pr = red + width;
    pg = green + width;
    pb = blue + width;
    
    while (--h) {
      r = *pr;
      rr = r + (r >> 1);
      if (rr < r) rr = ~0;
      g = *pg;
      gg = g + (g >> 1);
      if (gg < g) gg = ~0;
      b = *pb;
      bb = b + (b >> 1);
      if (bb < b) bb = ~0;
      
      *(++pr) = rr;
      *(++pg) = gg;
      *(++pb) = bb;
      
      pr += width - 3;
      pg += width - 3;
      pb += width - 3;
      
      r = *pr;
      rr = (r >> 2) + (r >> 1);
      if (rr > r) rr = 0;
      g = *pg;
      gg = (g >> 2) + (g >> 1);
      if (gg > g) gg = 0;
      b = *pb;
      bb = (b >> 2) + (b >> 1);
      if (bb > b) bb = 0;
      
      *(pr++) = rr;
      *(pg++) = gg;
      *(pb++) = bb;
      
      pr++; pg++; pb++;
    }
  }
}


void BImage::invert(void) {
  register unsigned int i, j, wh = (width * height) - 1;
  unsigned char tmp;

  for (i = 0, j = wh; j > i; j--, i++) {
    tmp = *(red + j);
    *(red + j) = *(red + i);
    *(red + i) = tmp;
    
    tmp = *(green + j);
    *(green + j) = *(green + i);
    *(green + i) = tmp;
    
    tmp = *(blue + j);
    *(blue + j) = *(blue + i);
    *(blue + i) = tmp;
  }
}


void BImage::dgradient(void) {
  float fr = (float) from.red,
    fg = (float) from.green,
    fb = (float) from.blue,
    tr = (float) to.red,
    tg = (float) to.green,
    tb = (float) to.blue,
    w = (float) (width * 2),
    h = (float) (height * 2),
    yr = 0.0,
    yg = 0.0,
    yb = 0.0,
    xr, xg, xb, drx, dgx, dbx, dry, dgy, dby;
  unsigned char *pr = red, *pg = green, *pb = blue;
  
  register unsigned int x, y;
  
  drx = dry = (tr - fr);
  dgx = dgy = (tg - fg);
  dbx = dby = (tb - fb);

  drx /= w;
  dgx /= w;
  dbx /= w;

  dry /= h;
  dgy /= h;
  dby /= h;

  for (y = 0; y < height; y++) {
    xr = fr + yr;
    xg = fg + yg;
    xb = fb + yb;
    
    for (x = 0; x < width; x++) {   
      *(pr++) = (unsigned char) (xr);
      *(pg++) = (unsigned char) (xg);
      *(pb++) = (unsigned char) (xb);
      
      xr += drx;
      xg += dgx;
      xb += dbx;
    }
    
    yr += dry;
    yg += dgy;
    yb += dby;
  }
}


void BImage::hgradient(void) {
  float fr, fg, fb, tr, tg, tb, drx, dgx, dbx, xr, xg, xb, w = (float) width;
  unsigned char *pr, *pg, *pb, *rr, *gg, *bb;

  register unsigned int x, y;

  xr = fr = (float) from.red;
  xg = fg = (float) from.green;
  xb = fb = (float) from.blue;

  tr = (float) to.red;
  tg = (float) to.green;
  tb = (float) to.blue;

  drx = (tr - fr) / w;
  dgx = (tg - fg) / w;
  dbx = (tb - fb) / w;

  pr = red;
  pg = green;
  pb = blue;

  // this renders one line of the hgradient
  for (x = 0; x < width; x++) {
    *(pr++) = (unsigned char) (xr);
    *(pg++) = (unsigned char) (xg);
    *(pb++) = (unsigned char) (xb);
    
    xr += drx;
    xg += dgx;
    xb += dbx;
  }

  // and this copies to the rest of the image
  for (y = 1; y < height; y++) {
    rr = red;
    gg = green;
    bb = blue;
    
    for (x = 0; x < width; x++) {
      *(pr++) = *(rr++);
      *(pg++) = *(gg++);
      *(pb++) = *(bb++);
    }
  }
}


void BImage::vgradient(void) {
  float fr, fg, fb, tr, tg, tb, dry, dgy, dby, yr, yg, yb,
    h = (float) height;
  unsigned char *pr = red, *pg = green, *pb = blue;
  
  register unsigned char r, g, b;
  register unsigned int x, y;
  
  yr = fr = (float) from.red;
  yg = fg = (float) from.green;
  yb = fb = (float) from.blue;

  tr = (float) to.red;
  tg = (float) to.green;
  tb = (float) to.blue;

  dry = (tr - fr) / h;
  dgy = (tg - fg) / h;
  dby = (tb - fb) / h;

  for (y = 0; y < height; y++) {
    yr += dry;
    yg += dgy;
    yb += dby;
      
    r = (unsigned char) (yr);
    g = (unsigned char) (yg);
    b = (unsigned char) (yb);
    
    for (x = 0; x < width; x++) {
      *(pr++) = r;
      *(pg++) = g;
      *(pb++) = b;
    }
  }
}


BImageControl::BImageControl(Basewindow *bb) {
  blackbox = bb;
  display = blackbox->getDisplay();
  screen_depth = blackbox->getDepth();
  window = blackbox->getRootWindow();
  screen_number = blackbox->getScreenNumber();

  colors = 0;
  colors_per_channel = ncolors = 0;
  
  int count;
  XPixmapFormatValues *pmv = XListPixmapFormats(display, &count);
  root_colormap = DefaultColormap(display, screen_number);
  
  if (pmv) {
    bits_per_pixel = 0;
    for (int i = 0; i < count; i++)
      if (pmv[i].depth == screen_depth) {
      bits_per_pixel = pmv[i].bits_per_pixel;
      break;
      }
  }
  
  if (bits_per_pixel == 0) bits_per_pixel = screen_depth;
  if (pmv) XFree(pmv);

  red_offset = green_offset = blue_offset = 0;

  switch (blackbox->getVisual()->c_class) {
  case TrueColor:
    {
      int i;

      // compute tables for red channel
      unsigned long mask = blackbox->getVisual()->red_mask, emask = mask;
      while (! (mask & 1)) { red_offset++; mask >>= 1; }
      for (i = 0; i < 256; i++) {
      rmask_table[i] = (i * mask + 0x7f) / 0xff;
      rerr_table[i] = ((rmask_table[i] << 8) / (emask >> red_offset));
      }
      
      // compute tables for green channel
      emask = mask = blackbox->getVisual()->green_mask;
      while (! (mask & 1)) { green_offset++; mask >>= 1; }
      for (i = 0; i < 256; i++) {
      gmask_table[i] = (i * mask + 0x7f) / 0xff;
      gerr_table[i] = ((gmask_table[i] << 8) / (emask >> green_offset));
      }
      
      // compute tables for blue channel
      emask = mask = blackbox->getVisual()->blue_mask;
      while (! (mask & 1)) { blue_offset++; mask >>= 1; }
      for (i = 0; i < 256; i++) {
      bmask_table[i] = (i * mask + 0x7f) / 0xff;
      berr_table[i] = ((bmask_table[i] << 8) / (emask >> blue_offset));
      }
    }
    
    break;
    
  case PseudoColor:
  case StaticColor:
    {
      colors_per_channel = blackbox->getColorsPerChannel();
      ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
      
      if (ncolors > (1 << screen_depth)) {
      colors_per_channel = (1 << screen_depth) / 3;
      ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
      }
      
      if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
      fprintf(stderr,
            "BImageControl::BImageControl: invalid colormap size %d "
            "(%d/%d/%d) - reducing",
                ncolors, colors_per_channel, colors_per_channel,
                colors_per_channel);

        colors_per_channel = (1 << screen_depth) / 3; 
      }
      
      colors = new XColor[ncolors];
      if (! colors) {
      fprintf(stderr, "BImageControl::BImageControl: error allocating "
            "colormap\n");
      exit(1);
      }

      int i = 0, ii, p, r, g, b;
      unsigned long mask = colors_per_channel - 1;
      for (i = 0; i < 256; i++) {
      rmask_table[i] = gmask_table[i] = bmask_table[i] =
        (i * mask + 0x7f) / 0xff;
      rerr_table[i] = gerr_table[i] = berr_table[i] =
        ((rmask_table[i] << 8) / (mask));
      }
      
      for (r = 0, i = 0; r < colors_per_channel; r++)
      for (g = 0; g < colors_per_channel; g++)
        for (b = 0; b < colors_per_channel; b++, i++) {
          colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
          colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
          colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
          colors[i].flags = DoRed|DoGreen|DoBlue;
        }
      
      blackbox->grab();
      
      for (i = 0; i < ncolors; i++)
      if (! XAllocColor(display, root_colormap, &colors[i])) {
        fprintf(stderr, "couldn't alloc color %i %i %i\n", colors[i].red,
              colors[i].green, colors[i].blue);
        colors[i].flags = 0;
      } else
        colors[i].flags = DoRed|DoGreen|DoBlue;
      
      blackbox->ungrab();
      
      XColor icolors[256];
      int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
      
      for (i = 0; i < incolors; i++)
      icolors[i].pixel = i;
      
      XQueryColors(display, root_colormap, icolors, incolors);
      for (i = 0; i < ncolors; i++) {
      if (! colors[i].flags) {
        unsigned long chk = 0xffffffff, pixel, close = 0;
        
        p = 2;
        while (p--) {
          for (ii = 0; ii < incolors; ii++) {
            r = (colors[i].red - icolors[i].red) >> 8;
            g = (colors[i].green - icolors[i].green) >> 8;
            b = (colors[i].blue - icolors[i].blue) >> 8;
            pixel = (r * r) + (g * g) + (b * b);
            
            if (pixel < chk) {
            chk = pixel;
            close = ii;
            }
            
            colors[i].red = icolors[close].red;
            colors[i].green = icolors[close].green;
            colors[i].blue = icolors[close].blue;
            
            if (XAllocColor(display, root_colormap, &colors[i])) {
            colors[i].flags = DoRed|DoGreen|DoBlue;
            break;
            }
          }
        }
      }
      }

      break;
    }
    
  case GrayScale:
  case StaticGray:
    fprintf(stderr, "BImageControl::BImageControl: GrayScale/StaticGray "
                    "visual unsupported\n");
    break;
    
  default:
    fprintf(stderr, "BImageControl::BImageControl: unsupported visual %d\n",
          blackbox->getVisual()->c_class);
    exit(1);
  }
  
  cache = new LinkedList<Cache>;
  
  dither_buf_width = 0;
  red_err = green_err = blue_err = next_red_err = next_green_err =
    next_blue_err = 0;
}


BImageControl::~BImageControl(void) {
  if (red_err) delete [] red_err;
  if (green_err) delete [] green_err;
  if (blue_err) delete [] blue_err;
  if (next_red_err) delete [] next_red_err;
  if (next_green_err) delete [] next_green_err;
  if (next_blue_err) delete [] next_blue_err;

  if (colors) {
    unsigned long *pixels = new unsigned long [ncolors];

    int i;
    for (i = 0; i < ncolors; i++)
      *(pixels + i) = (*(colors + i)).pixel;

    XFreeColors(display, DefaultColormap(display, screen_number),
            pixels, ncolors, 0);

    delete [] colors;
  }

  if (cache->count()) {
    int i, n = cache->count();
    fprintf(stderr, "BImageContol::~BImageControl: pixmap cache - "
          "releasing %d pixmaps\n", n);
    
    for (i = 0; i < n; i++) {
      Cache *tmp = cache->first();
      XFreePixmap(display, tmp->pixmap);
      cache->remove(tmp);
      delete tmp;
    }
  }
  
  delete cache;
}


Bool BImageControl::doDither(void) {
  return blackbox->hasImageDither();
}


Visual *BImageControl::getVisual(void) {
  return blackbox->getVisual();
}


Pixmap BImageControl::searchCache(unsigned int width, unsigned int height,
                          unsigned long texture, const BColor &c1,
                          const BColor &c2) {
  if (cache->count()) {
    LinkedListIterator<Cache> it(cache);

    for (; it.current(); it++) {
      if ((it.current()->width == width) &&
        (it.current()->height == height) &&
        (it.current()->texture == texture) &&
        (it.current()->pixel1 == c1.pixel))
      if (texture & BImage_Gradient) {
        if (it.current()->pixel2 == c2.pixel) {
          it.current()->count++;
          return it.current()->pixmap;
        }
      } else {
        it.current()->count++;
        return it.current()->pixmap;
      }
    }
  }

  return None;
}

Pixmap BImageControl::renderImage(unsigned int width, unsigned int height,
                          const BTexture *texture)
{
  Pixmap pixmap = searchCache(width, height, texture->texture,
                        texture->color, texture->colorTo);
  if (pixmap) return pixmap;
  
  BImage image(this, width, height);
  pixmap = image.render(texture);
  
  if (pixmap) {
    Cache *tmp = new Cache;

    tmp->pixmap = pixmap;
    tmp->width = width;
    tmp->height = height;
    tmp->count = 1;
    tmp->texture = texture->texture;
    tmp->pixel1 = texture->color.pixel;

    if (texture->texture & BImage_Gradient)
      tmp->pixel2 = texture->colorTo.pixel;
    else
      tmp->pixel2 = 0l;
    
    cache->insert(tmp);
    
    return pixmap;
  }
  
  return None;
}


void BImageControl::removeImage(Pixmap pixmap) {
  if (pixmap) {
    LinkedListIterator<Cache> it(cache);

    for (; it.current(); it++) {
      if (it.current()->pixmap == pixmap) {
      Cache *tmp = it.current();
      tmp->count--;
        
      if (! tmp->count) {       
        XFreePixmap(display, tmp->pixmap);
        cache->remove(tmp);
        delete tmp;
      }
      
      return;
      }
    }
  }
}


unsigned long BImageControl::getColor(const char *colorname,
                              unsigned char *r, unsigned char *g,
                              unsigned char *b)
{
  XColor color;
  color.pixel = 0;
  
  if (! XParseColor(display, DefaultColormap(display, screen_number),
                colorname, &color)) {
    fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
          colorname);
  } else if (! XAllocColor(display, DefaultColormap(display, screen_number),
                     &color)) {
    fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
          colorname);
  }
  
  if (color.red == 65535) *r = 0xff;
  else *r = (unsigned char) (color.red / 0xff);
  if (color.green == 65535) *g = 0xff;
  else *g = (unsigned char) (color.green / 0xff);
  if (color.blue == 65535) *b = 0xff;
  else *b = (unsigned char) (color.blue / 0xff);
  
  return color.pixel;
}


unsigned long BImageControl::getColor(const char *colorname) {
  XColor color;
  color.pixel = 0;

  if (! XParseColor(display, DefaultColormap(display, screen_number),
                colorname, &color)) {
    fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
          colorname);
  } else if (! XAllocColor(display, DefaultColormap(display, screen_number),
                     &color)) {
    fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
          colorname);
  }
  
  return color.pixel;
}


void BImageControl::getMaskTables(unsigned short **rmt, unsigned short **gmt,
                          unsigned short **bmt,
                          int *roff, int *goff, int *boff) {
  if (rmt) *rmt = rmask_table;
  if (gmt) *gmt = gmask_table;
  if (bmt) *bmt = bmask_table;

  if (roff) *roff = red_offset;
  if (goff) *goff = green_offset;
  if (boff) *boff = blue_offset;
}


void BImageControl::getColorTable(XColor **c, int *n) {
  if (c) *c = colors;
  if (n) *n = ncolors;
}


void BImageControl::getDitherBuffers(unsigned int w,
                             short **r, short **g, short **b,
                             short **nr, short **ng, short **nb,
                             unsigned short **ret,
                             unsigned short **get,
                             unsigned short **bet) {
  if (w > dither_buf_width) {
    if (red_err) delete [] red_err;
    if (green_err) delete [] green_err;
    if (blue_err) delete [] blue_err;
    if (next_red_err) delete [] next_red_err;
    if (next_green_err) delete [] next_green_err;
    if (next_blue_err) delete [] next_blue_err;
    
    dither_buf_width = w;
    
    red_err = new short[dither_buf_width];
    green_err = new short[dither_buf_width];
    blue_err = new short[dither_buf_width];
    next_red_err = new short[dither_buf_width];
    next_green_err = new short[dither_buf_width];
    next_blue_err = new short[dither_buf_width];
  }

  *r = red_err;
  *g = green_err;
  *b = blue_err;
  *nr = next_red_err;
  *ng = next_green_err;
  *nb = next_blue_err;
  *ret = rerr_table;
  *get = gerr_table;
  *bet = berr_table;
}


void BImageControl::installRootColormap(void) {
  blackbox->grab();
  
  Bool install = True;
  int i = 0, ncmap = 0;
  Colormap *cmaps = XListInstalledColormaps(display, window, &ncmap);
  
  if (cmaps) {
    for (i = 0; i < ncmap; i++)
      if (*(cmaps + i) == root_colormap)
      install = False;
    
    if (install)
      XInstallColormap(display, root_colormap);
    
    XFree(cmaps);
  }
  
  blackbox->ungrab();
}

Generated by  Doxygen 1.6.0   Back to index