diff pkg-src/tree-x/dbl.c @ 163:0132846995bd r20-3b8

Import from CVS: tag r20-3b8
author cvs
date Mon, 13 Aug 2007 09:43:35 +0200
parents
children 85ec50267440
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg-src/tree-x/dbl.c	Mon Aug 13 09:43:35 2007 +0200
@@ -0,0 +1,377 @@
+/* ----------------------------------------------------------------------------
+ *     Double buffering code
+ * ----------------------------------------------------------------------------
+ */
+
+
+#include "dbl.h"
+
+struct {                                               
+    unsigned short red;                                        
+    unsigned short green;
+    unsigned short blue;
+} color[] = {
+    { 65280, 65280, 65280 }, /* white  */                      
+    {     0,     0, 65280 }, /* blue   */
+    {     0, 65280,     0 }, /* green  */
+    { 65280,     0,     0 }, /* red    */
+    { 42240, 10752, 10752 }, /* brown  */
+    { 65280, 32512,     0 }, /* orange */
+    { 32512, 32512, 32512 }, /* gray   */
+    {     0,     0,     0 }  /* black  */
+};                       
+
+/* ------------------------------------------------------------------------- */
+
+DoubleBuffer *
+DBLcreate_double_buffer (display, window, backing_store, colors, num_colors)
+   Display *display;
+   Window   window;
+   int      backing_store;
+   XColor  *colors;
+   int      num_colors;
+{                                                                
+   int i, j, k, l, m, offset, mask, size;
+   int max_planes;
+
+   char         *string;
+   Surface     *surface;
+   DoubleBuffer     *db;
+   XGCValues       xgcv;
+   unsigned long   xgcvmask;
+
+/* allocate the double buffer structure,  and then open the display */
+
+   if ((db = (DoubleBuffer *)calloc(1, sizeof(DoubleBuffer))) == 0) {
+      printf("DBLopen_double_buffer : memory allocation error\n");
+      return (NULL);
+   }                                                          
+
+/* note the display */
+
+   db->display  = display;
+
+/* first some information about our display */
+
+   db->screen   = DefaultScreenOfDisplay(db->display);
+   db->window   = window;
+
+/* now get some information on color resources */
+
+   db->visual   = DefaultVisualOfScreen(db->screen);
+   db->depth    = DefaultDepthOfScreen(db->screen);
+   db->colormap = DefaultColormapOfScreen(db->screen);
+
+/* set up colors */
+
+   for (i = 0 ; i < num_colors; i++) {
+      color[i].red   = colors[i].red;
+      color[i].green = colors[i].green;
+      color[i].blue  = colors[i].blue;
+   }
+   
+/* see if the user wanted to limit the number of planes used
+   then see how many are available,  make it a multiple of 2 */
+
+   if ((string = getenv("DBL_MAX_PLANES")) == NULL)
+      max_planes = DBL_MAX_PLANES;
+   else {
+      max_planes = atoi(string);
+   }
+
+   if ((db->num_planes = PlanesOfScreen(db->screen)) > max_planes) {
+      db->num_planes = max_planes;
+   }
+
+   db->num_planes = (db->num_planes >> 1) << 1;
+
+
+/* otherwise allocate contiguous planes to do double buffering */
+
+   while (db->num_planes >= DBL_MIN_PLANES) {
+      if (XAllocColorCells (db->display, db->colormap, 1, db->planes,
+			    db->num_planes, db->pixels, 1)) {
+	 break;
+      }
+
+      db->num_planes -= 2;
+   }
+
+/* if we have at least minimum planes, then we can do double
+   buffering and we want to setup our surfaces and colormaps */
+
+   if (db->num_planes < DBL_MIN_PLANES)
+      db->num_surfaces = 0;
+   else {
+      db->num_colors   = 1 << (db->num_planes >> 1);
+      db->num_surfaces = DBL_MAX_SURFACES;
+
+   /* if the number of colors is less than DBL_MAX_COLORS,
+      then we want to make sure black is the  last  color */
+
+      for (i = db->num_colors - 1; i < DBL_MAX_COLORS; i++) {
+         color[i].red   = color[DBL_MAX_COLORS - 1].red;
+         color[i].green = color[DBL_MAX_COLORS - 1].green;
+         color[i].blue  = color[DBL_MAX_COLORS - 1].blue;
+      }
+
+   /* we have a set of contiguous planes.  compute a mask for
+      the planes,  and figure out the offset in the  hardware */
+
+      for (i = 0; i < db->num_planes; i++) {
+         db->mask |= db->planes[i];
+      }
+
+      mask   = db->mask;
+      offset = 0;
+
+      while ((mask & 1) == 0) {
+         mask = mask >> 1;
+         offset = offset + 1;
+      }
+
+      mask = (1 << (db->num_planes >> 1)) - 1;                             
+
+   /* now create the surfaces that will contain plane mask and
+      colormap information that we use to do double  buffering */
+
+      for (i = 0; i < db->num_surfaces; i++) {
+         size = sizeof(Surface) + sizeof(XColor) * (1 << db->num_planes);
+
+         if ((surface = (Surface *)malloc(size)) != NULL)
+            db->surface[i] = surface;
+         else {
+            printf("DBLcreate_double_buffer : memory allocation error\n");
+            DBLdelete_double_buffer(db);
+            return(NULL);
+         }
+
+         surface->offset     = offset + i * (db->num_planes >> 1);
+         surface->mask       = mask << surface->offset;
+         surface->num_colors = 1 << db->num_planes;
+  
+      /* compute our pixel values by taking every permutation
+         of the pixel and planes returned by XAllocColorCells */
+
+         for (j = 0; j < (surface->num_colors); j++) {
+            surface->color[j].pixel = db->pixels[0];
+         }
+
+         for (j = 0; j < db->num_planes; j++) {
+            for (k = (1 << j); k < (surface->num_colors); k += (2 << j)) {
+               for (l = k; l < (k + (1 << j)); l++) {                  
+                  surface->color[l].pixel |= db->planes[j];
+               }
+            }
+         }
+
+       /* now populate those pixels with the proper  colors  so             
+          that we can do animation by banging in a new colormap */
+
+         for (j = 0; j < surface->num_colors; j++) {
+            k = (j & surface->mask) >> surface->offset;
+
+            surface->color[j].red   = color[k].red;                 
+            surface->color[j].green = color[k].green;
+            surface->color[j].blue  = color[k].blue;
+
+            surface->color[j].flags = DoRed | DoGreen | DoBlue;
+         }
+      }
+
+      db->current_surface = 0;
+   }
+
+
+/* now figure out what pixel values we will use to draw with
+   and store them in the double buffer structure */
+
+   if (db->num_surfaces == 0) {
+      db->num_colors = DBL_MAX_COLORS;
+      db->colors[0]  = WhitePixelOfScreen(db->screen);
+
+      for (i = 1; i < db->num_colors; i++) {
+	 db->colors[i] = BlackPixelOfScreen(db->screen);
+      }
+   }
+   else {
+      for (i = 0; i < db->num_colors; i++) {
+         j = (i << (db->num_planes >> 1)) + i;
+         db->colors[i] = db->surface[0]->color[j].pixel;
+      }
+   }
+
+/* fill out the remaining colors with the last color */
+
+   for (; i < DBL_MAX_COLORS; i++) {
+      db->colors[i] = db->colors[db->num_colors - 1];
+   }
+
+   db->width   = WidthOfScreen(db->screen);
+   db->height  = HeightOfScreen(db->screen);
+
+/* if there are no surfaces then we are doing animation with
+   a frame buffer,  so create a pixmap as our frame buffer   */
+                         
+   if (db->num_surfaces > 0)
+      db->drawable = db->window;   
+   else {
+      db->frame = XCreatePixmap(db->display, db->window,
+				db->width, db->height, db->depth);
+      db->drawable = db->frame;
+   }                                                                    
+
+/* if they have requested backing store,  then create an extra
+   pixmap which we can use as backing store to handle exposures */
+
+   if (backing_store) {
+      db->backing = XCreatePixmap(db->display, db->window,
+				  db->width, db->height, db->depth);
+   }                                                   
+
+/*  use the 0 pixel from one of the surfaces for the background */
+
+   xgcv.background = DBLinq_background(db);
+   xgcv.line_style = LineSolid;
+   xgcv.line_width = 0;
+   xgcv.cap_style  = CapButt;
+   xgcv.join_style = JoinRound;
+   xgcvmask = GCBackground | GCLineStyle | GCLineWidth | GCCapStyle | 
+              GCJoinStyle;
+   
+   db->gc = XCreateGC(db->display, db->drawable, xgcvmask, &xgcv);
+
+/* do an initial frame to setup the colormap,  and return */
+
+   DBLbegin_frame(db);
+   DBLend_frame(db, 1);
+   return (db);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void
+DBLdelete_double_buffer (db)
+     DoubleBuffer *db;
+{
+  int i;
+
+  /* remove and and all surfaces that are out there */
+  
+  for (i = 0; i < DBL_MAX_SURFACES; i++) {
+    if (db->surface[i] != 0) {
+      free(db->surface[i]);                               
+    }
+  }
+
+  /* now clean up the various resources used for this double buffer */
+  
+  if (db->frame != 0) {
+    XFreePixmap(db->display, db->frame);
+  }
+  
+  if (db->backing != 0) {
+    XFreePixmap(db->display, db->backing);
+  }
+  
+  /* if we created our own private colormap,  then free the colormap */
+  
+  if (db->colormap != DefaultColormapOfScreen(db->screen)) {
+    XFreeColormap(db->display, db->colormap);
+  }
+  
+  free (db);
+}
+
+/* ------------------------------------------------------------------------- */
+
+unsigned long
+DBLinq_background(db)
+   DoubleBuffer *db;
+{
+   if (db->num_surfaces > 0)
+      return(db->surface[0]->color[0].pixel);
+   else 
+      return(WhitePixelOfScreen(db->screen));
+}
+
+/* ------------------------------------------------------------------------- */
+
+DBLbegin_frame(db)
+     DoubleBuffer *db;
+{
+  Surface   *surface;
+  
+  /* there will be at most two surfaces optimize with "&"*/
+  
+  if (db->num_surfaces > 0) {                       
+    db->current_surface = (db->current_surface + 1) & 1;                  
+    surface = db->surface[db->current_surface];
+  }
+   
+  /* clear the back surface of the window which may actually be a pixmap */ 
+  
+  if (db->num_surfaces > 0) 
+    XSetPlaneMask (db->display, db->gc, surface->mask);
+  
+  /* clear out the back surface or frame buffer as appropriate */
+  
+  XSetFunction(db->display, db->gc, GXclear);
+  XFillRectangle(db->display, db->drawable, db->gc,
+		 0, 0, db->width, db->height);
+  
+  /* set writing mode back to copy */
+  XSetFunction (db->display, db->gc, GXcopy);
+  
+  XSync(db->display, False);
+}  
+         
+
+/* ------------------------------------------------------------------------- */
+                                            
+
+DBLend_frame(db, init)
+     DoubleBuffer *db;                                                   
+     short init;
+{
+  Surface  *surface;
+  
+  /* if there are no drawing surfaces,  then we are doing animation   
+     with a frame buffer, copy the frame buffers to their viewports */
+
+  if (db->num_surfaces == 0) {
+     if (! init)
+        XCopyArea (db->display, db->frame, db->window,
+	           db->gc, 0,0, db->width, db->height, 0,0);
+  } else {
+    
+    /* otherwise,  we can flip the surface by banging in the new colormap */
+
+    XSync(db->display, False);
+    surface = db->surface[db->current_surface];
+    XStoreColors (db->display, db->colormap,
+		  surface->color, surface->num_colors);
+  }
+
+  if (db->backing != 0) {
+    XCopyArea (db->display, db->window, db->backing,
+	       db->gc, 0,0, db->width, db->height, 0,0);
+  }
+  
+  /* make sure this all goes off to the server,  right away */
+  
+  XSync(db->display, False);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+