XGL Programmer's Guide
この本のみを検索
PDF 文書ファイルをダウンロードする

Color

6

This chapter discusses the XGL Color Models and Color Map object, and includes information on the following topics:
  • Indexed and RGB Color
  • XGL color pipeline
  • Color Map double buffering
This chapter provides examples using a color table, a color ramp, a color cube, and color map double buffering

Introduction to XGL Color

The XGL color scheme is built around the fundamental concept that XGL Rasters represent underlying hardware display devices. XGL Raster objects, therefore, are closely tied to the capabilities of the hardware. XGL Raster objects help free the application programmer from dealing with the hardware directly while providing a consistent interface for performing rendering operations. Because XGL Raster objects were designed to parallel the hardware, Rasters support the two most often used color models: indexed and RGB.

Indexed Color Space

The indexed color model uses a color lookup table to map index values to corresponding RGB values. A lookup table is an array containing a finite number of RGB colors or gray shades for display on the hardware. Each pixel to be rendered on the display device has an associated index. Before the pixel is displayed, the color for the pixel is retrieved from the lookup table using the index as a pointer to the appropriate values. Indexed color is known as indirect color because the displayed color is determined indirectly through a color lookup table.

RGB Color Space

RGB does not require a lookup table. The individual pixel's color is specified as a fractional component of each of the three monitor primary colors: red, green, and blue. Each component is a number between 0.0 and 1.0, and represents the additive weight the specific primary color contributes to the final color. Because the component values directly specify pixel color to the hardware, RGB is also known as direct color.

XGL Color Pipeline

The XGL color pipeline defines how colors are moved from the application's color space (or color type) to the device color type. The application's color type is defined with respect to the XGL Raster Device object attached to the current XGL Context. The color type for Rasters is set at Raster creation time. The hardware color type is fixed to the device characteristics, and is unchangeable.
If the color type requested by the application for the Raster is the same as the color type of the underlying hardware, no conversion is necessary. The color values of the pixels to be displayed are passed to the hardware without modification.
If the application's color type is different from the hardware color type, a color conversion is required. The conversion can take place before or after XGL performs the rendering calculations, depending on the capabilities of the underlying hardware. Color conversion for Memory Rasters is always done before rendering.
Two cases of color type conversion are possible. In one case, the application can request RGB colors when the underlying hardware is indexed. In this case, the RGB-to-indexed conversion is done using a color cube stored in an XGL Color Map object. In the second case of color type conversion, the application requests indexed colors, and the underlying hardware is RGB. In this case, indexed-to-RGB conversion is required. The conversion is carried out using a color table stored in the XGL Color Map object.
The XGL Context color type must be the same as the color type of its associated Raster. Therefore, only one color type conversion is required when going from application color space to hardware color space. Figure 6-1 illustrates the two types of color conversion.

グラフィック

Figure 6-1

Introduction to the Color Map Object

The XGL Color Map object permits an application programmer to add color to an XGL application. It defines color value conversions from one color type to another. Conversions are performed using either a color lookup table or a mapper function attached to the Color Map object. The color lookup table is normally used for indexed-to-RGB conversions, and the mapper function for RGB-to-indexed conversions.
Indexed Rasters must have a Color Map object associated with them. When the application creates an Raster object for an indexed raster, XGL attaches a default Color Map to the Raster if the application has not specified an application-created Color Map for the Raster.
RGB Rasters require a Color Map object only if the underlying display hardware is indexed. XGL attaches a default Color Map to an RGB Raster object only when the underlying hardware is indexed and the application program does not supply a Color Map.

Note - When using an indexed 8-bit Memory Raster to copy into an indexed 24-bit Window Raster, a separate Color Map object is required for each raster. Since XGL does internal color map conversion, which is different in these cases, the same color map cannot be used when the underlying hardware is different.

Creating a Color Map Object

The operator xgl_object_create(), with XGL_CMAP as the value for the parameter type, creates an XGL Color Map object. The desc parameter is ignored and can be set to NULL. As with all XGL objects, Color Map attributes can be set within the create call or with a separate xgl_object_set() command. The following code line shows Color Map object creation:

  new_cmap = xgl_object_create(sys_st, XGL_CMAP, NULL, NULL);  

Color Map objects are associated only with Raster and Metafile objects. A Color Map object is associated with a Device object with the XGL_DEV_COLOR_MAP attribute. This association can be set with an xgl_object_set() command, as in the following code line:

  ras = xgl_object_set(ras, XGL_DEV_COLOR_MAP, new_cmap, NULL);  

The two objects can also associated when the Raster is created, as in the following example:

  xgl_object_create(sys_st, XGL_WIN_RAS, &obj_desc,  
                    XGL_DEV_COLOR_TYPE, XGL_COLOR_INDEX,  
                    XGL_DEV_COLOR_MAP, new_cmap,  
                    NULL);  

Color Tables

Most XGL applications exclusively use indexed Rasters, because most current hardware frame buffers are indexed. For indexed Rasters, the color table associated with the Raster Color Map object maps colors from the indexed frame buffer to the display device. The default color table, initialized at the creation of the Raster Color Map object, is a two-element, black-and-white color table. The following sections emphasize the use of indexed Rasters and the color table.

Color Table Attributes

The XGL Color Map object includes several attributes specific to color tables. The attribute XGL_CMAP_COLOR_TABLE specifies the color table that is to be attached to the Color Map object. XGL_CMAP_COLOR_TABLE_SIZE specifies the size of the color table and must be set prior to setting the color map with XGL_CMAP_COLOR_TABLE. The value of XGL_CMAP_COLOR_TABLE_SIZE should be greater than or equal to the sum of the start index and length structure elements passed with XGL_CMAP_COLOR_TABLE. Generally, the XGL_CMAP_COLOR_TABLE_SIZE attribute is set to a value that is a power of 2. If it exceeds the maximum size allowed by the hardware (as specified by XGL_CMAP_MAX_COLOR_TABLE_SIZE), then XGL sets this attribute to that maximum value.

Creating a Color Table

An XGL color table is formatted as a C structure of type Xgl_color_list containing a starting index of the color table, a color table length, and an array of Xgl_color values that comprise the heart of the color table. The contents of the array are specified as RGB color values. The color table structure is defined as:

  /* XGL color table structure */  
  typedef struct {  
    Xgl_usgn32     start_index;  
    Xgl_usgn32     length;  
    Xgl_color      *colors;  
  } Xgl_color_list;  

The following code fragment creates an XGL Color Map object and attaches a color table to it.
/* colors to use in color table */
Xgl_color_rgb            GOLD = {1.00, 0.20, 0.00};
Xgl_color_rgb            GOLDENROD =  {1.00, 0.36, 0.00};
Xgl_cmap                 ex_cmap;           /* color map object */
Xgl_color_list           ex_cmap_info;      /* color table */
Xgl_color                x_color_table[2]; /* color table array */
int                      i = 0;             /* index into array */

/* create color map object */
GBL_cmap = xgl_object_create(sys_st, XGL_CMAP, NULL, NULL);

/* initialize color array */
GBL_color_table[i++].rgb = GOLD;
GBL_color_table[i].rgb = GOLDENROD;

/* initialize color table struct */
GBL_cmap_info.start_index = 0;
GBL_cmap_info.length = 2;
GBL_cmap_info.colors = ex_color_table;

/* attach color table to color map object */
xgl_object_set(GBL_cmap,
                XGL_CMAP_COLOR_TABLE_SIZE, 2,
                XGL_CMAP_COLOR_TABLE, &ex_cmap_info,
                NULL);

Simple Color Table Example

The following example, color_simple.c, shows the basic features of a Color Map object. The example illustrates how to create a color table containing eight elements and a Color Map object using that color table. It also illustrates how to draw a series of eight rectangles, each using a different color from the color table.
The code in Code Example 6-1 is a part of a complete program that includes ex_utils.c and color_main.c, both of which are listed in Appendix B. To compile this program, type make color in the example program directory. The output of this program can be seen on Plate 3a.
Code Example 6-1 Simple Color Example
/*
 * color_simple.c
 */

#include <xview/xview.h>
#include <xgl/xgl.h>

#include "ex.h"

extern Xgl_rect_i2d     recti2d[256];
extern Xgl_rect_list    rectlist;
extern Xgl_cmap         simplecmap;

#defineCMAPSIZE8
#define RECTSIZE56

void
color_simple (Xgl_object ctx)
{
    Xgl_sgn32            i;
    Xgl_ras              ras;   /* raster associated with ctx */
    Xgl_color            ecolor, rgb_colors[8];

    /*
     * get raster object from context
     */
    xgl_object_get (ctx, XGL_CTX_DEVICE, &ras);

    /*

     * Set 8 colors: black, red, green, blue, yellow, cyan,
     * magenta, white
     */
    rgb_colors[0].rgb.r = 0.0;
    rgb_colors[0].rgb.g = 0.0;
    rgb_colors[0].rgb.b = 0.0;
    rgb_colors[1].rgb.r = 1.0;
    rgb_colors[1].rgb.g = 0.0;
    rgb_colors[1].rgb.b = 0.0;
    rgb_colors[2].rgb.r = 0.0;
    rgb_colors[2].rgb.g = 1.0;
    rgb_colors[2].rgb.b = 0.0;
    rgb_colors[3].rgb.r = 0.0;
    rgb_colors[3].rgb.g = 0.0;
    rgb_colors[3].rgb.b = 1.0;
    rgb_colors[4].rgb.r = 1.0;
    rgb_colors[4].rgb.g = 1.0;
    rgb_colors[4].rgb.b = 0.0;
    rgb_colors[5].rgb.r = 0.0;
    rgb_colors[5].rgb.g = 1.0;
    rgb_colors[5].rgb.b = 1.0;
    rgb_colors[6].rgb.r = 1.0;
    rgb_colors[6].rgb.g = 0.0;
    rgb_colors[6].rgb.b = 1.0;
    rgb_colors[7].rgb.r = 1.0;
    rgb_colors[7].rgb.g = 1.0;
    rgb_colors[7].rgb.b = 1.0;

    /*
     * if color map associated with raster isn't simplecmap
     * then put it into the raster
     */
    if (ex_color_type == XGL_COLOR_INDEX && !simplecmap) {
        Xgl_color_list       clist;      /* color table list */

        /*
         * set up color list
         */
        clist.start_index = 0;
        clist.length = 8;
        clist.colors = rgb_colors;

        /*
         * create simple color map object and set the
         * color table to our new colors
         */

        simplecmap = xgl_object_create (sys_st, XGL_CMAP, NULL,
                     XGL_CMAP_COLOR_TABLE_SIZE, 8,
                     XGL_CMAP_COLOR_TABLE, &clist,
                     NULL);
    }

    /*
     * turn on edges to show color entries better
     */
    ecolor = white_color;
    xgl_object_set (ctx, XGL_CTX_SURF_EDGE_FLAG, TRUE,
             XGL_CTX_EDGE_COLOR, &ecolor,
             NULL);

    if (ex_color_type == XGL_COLOR_INDEX) {
        /*
         * put simple color map into raster
         */
        xgl_object_set (ras, XGL_RAS_COLOR_MAP, simplecmap, NULL);
    }

    rectlist.num_rects = 1;
    rectlist.rect_type = XGL_MULTIRECT_I2D;
    rectlist.bbox = NULL;

    xgl_object_set (ctx, XGL_CTX_PLANE_MASK, -1,
                         XGL_CTX_VDC_MAP, XGL_VDC_MAP_DEVICE, NULL);

    xgl_context_new_frame (ctx);

    /* Draw rectangles to display color map */
    for (i = 0; i < CMAPSIZE; i++) {
        Xgl_color            rectcolor;

        recti2d[i].corner_min.x = i * RECTSIZE;
        recti2d[i].corner_min.y = 0;
        recti2d[i].corner_min.flag = 1;
        recti2d[i].corner_max.x = (i * RECTSIZE) + (RECTSIZE - 1);
        recti2d[i].corner_max.y = RECTSIZE;

        rectlist.rects.i2d = &recti2d[i];

        if (ex_color_type == XGL_COLOR_INDEX)
            rectcolor.index = i;
       else {
           rectcolor = rgb_colors[i];

      }

      xgl_object_set (ctx,
            XGL_CTX_SURF_FRONT_COLOR, &rectcolor,
            NULL);

      xgl_multirectangle (ctx, &rectlist);
    }

    xgl_object_set (ctx, XGL_CTX_SURF_EDGE_FLAG, FALSE, NULL);
}

Color Table Ramps

Color tables can have color ramps embedded in them. A color ramp is a section of the color table of a specific length used to store color values that change by intensity only. For example, a gray ramp could have 32 color values from dark gray to light gray in a monotonically increasing fashion.
Ramps limit the range of valid indices used for indexed lighting and shading, and prevent overflow or underflow of color values. If an index defining the vertex colors in an XGL primitive is in a ramp, the frame buffer color values produced by the lighting and shading are limited to fall within the minimum and maximum index values of the ramp. Ramps are also important in lighting, shading, and depth cueing in indexed rasters.

Creating Color Table Ramps

An XGL color ramp is specified by using the C structure Xgl_segment, which contains an offset into the color table where the ramp begins, and the length of the ramp. If more than one ramp exists in the color table, an array of Xgl_segment structures is required, with each member of the array defining each ramp.The Xgl_segment structure is defined as:

  /* XGL structure for defining ramps in color table */  
  typedef struct {  
    Xgl_usgn32     offset;  
    xgl_usgn32     length;  
  } Xgl_segment;  

The number of ramps in the color table is set using the Color Map attribute XGL_CMAP_RAMP_NUM, and a pointer to the array of Xgl_segment structures associated with the ramps must be specified by setting the attribute
XGL_CMAP_RAMP_LIST.

The following code fragment shows the steps required to add ramps to an XGL Color Map object. The first step initializes the section of the color table associated with each ramp. Then the Xgl_segment structures are initialized. Finally, the Color Map is created.
Xgl_cmap             GBL_cmap;      /* Color Map object */
Xgl_color_list       GBL_cmap_info; /* color table */
Xgl_color            GBL_color_table[128]; /* color table array */
int                  i;             /* index into array */
Xgl_segment          segments[4];   /* color ramps */

/* initialize color array */
/* create red ramp */
for (i = 0; i < 16; i++) {
  GBL_color_table[i].rgb.r = ((float)(i) / 15.0);
  GBL_color_table[i].rgb.g = GBL_color_table[i].rgb.b = 0.0;
}

/* create green ramp */
for (i = 16; i < 32; i++) {
  GBL_color_table[i].rgb.g = ((float)(i - 16) / 15.0);
  GBL_color_table[i].rgb.r = GBL_color_table[i].rgb.b = 0.0;
}
/* create blue ramp */
for (i = 32; i < 64; i++) {
  GBL_color_table[i].rgb.b = ((float)(i - 32) / 31.0);
  GBL_color_table[i].rgb.r = GBL_color_table[i].rgb.g = 0.0;
}
/* create gray ramp */
for (i = 64; i < 128; i++) {
  GBL_color_table[i].rgb.r =
  GBL_color_table[i].rgb.g =
  GBL_color_table[i].rgb.b = ((float)(i - 64) / 63.0);
}

/* initialize ramp structure */
segments[0].offset = 0; /* red ramp */
segments[0].length = 16;
segments[1].offset = 16;/* green ramp */

segments[1].length = 16;
segments[2].offset = 32;/* blue ramp */
segments[2].length = 32;
segments[3].offset = 64;/* gray ramp */
segments[3].length = 64;

/* initialize color table struct */
GBL_cmap_info.start_index = 0;
GBL_cmap_info.length = 128;
GBL_cmap_info.colors = GBL_color_table;

/* create Color Map object and attach color table to it */
GBL_cmap = xgl_object_create(sys_st, XGL_CMAP, NULL,
                  XGL_CMAP_COLOR_TABLE_SIZE, 128,
                  XGL_CMAP_RAMP_NUM, 4,
                  XGL_CMAP_RAMP_LIST, segments,
                  XGL_CMAP_COLOR_TABLE, &GBL_cmap_info,
                  NULL);

Color Ramp Example

The following example, color_ramp.c, shows how color ramps can be created and used in an XGL application. The code in Code Example 6-2 is a part of a complete program that includes ex_utils.c and color_main.c, both of which are listed in Appendix B. To compile this program, type make color in the example program directory. The output of this program can be seen on Plate 3b.
Code Example 6-2 Color Ramp Example
/*
 * color_ramp.c
 */

#include <xview/xview.h>
#include <xgl/xgl.h>

#include "ex.h"

#define RAMP_SIZE16

extern Xgl_pt_list            pl_3d;
extern Xgl_object             rampcmap;

void
color_ramp (Xgl_object   ctx)
{
    Xgl_object           ras;          /* raster associated with ctx */
    Xgl_object           cmap;         /* color map associated with ras */
    Xgl_color            ln_color; /* vector color */
    Xgl_object           view_trans;

    /*
     * get raster object from context
     */
    xgl_object_get (ctx, XGL_CTX_DEVICE, &ras);

    if (ex_color_type == XGL_COLOR_INDEX) {

   /*
    * get color map object from raster
    */
   xgl_object_get (ras, XGL_RAS_COLOR_MAP, &cmap);

   /*
    * if color map associated with raster isn't rampcmap then put
    * it into the raster
    */
   if (cmap != rampcmap) {

      if (!rampcmap) {
        Xgl_sgn32             i;
        Xgl_color_list        clist;       /* color table list */
        Xgl_color             colors[RAMP_SIZE];/* list of colors */
        Xgl_segment           segment;     /* color ramp segment */

        /*
         * create color list
         */
        clist.start_index = 0;
        clist.length      = RAMP_SIZE;
        clist.colors      = colors;

        /*
         * gray ramp for depth cued vectors
         */
        for (i = 0; i < RAMP_SIZE; i++) {
            colors[i].rgb.r =
            colors[i].rgb.g =

            colors[i].rgb.b = ((float) i) / ((float)(RAMP_SIZE - 1));
        }

        /*
         * setup segment data
         */
        segment.offset = 0;
        segment.length = RAMP_SIZE;

        /*
         * create and set attributes for ramp color map
         */
        rampcmap = xgl_object_create(sys_st, XGL_CMAP, NULL,
                      XGL_CMAP_COLOR_TABLE_SIZE, RAMP_SIZE,
                      XGL_CMAP_COLOR_TABLE, &clist,
                      XGL_CMAP_RAMP_NUM, 1,
                      XGL_CMAP_RAMP_LIST, &segment,
                      NULL);
        }

       /*
        * set color map in raster
        */
       xgl_object_set (ras, XGL_RAS_COLOR_MAP, rampcmap, NULL);
      }

    } else {/* RGB raster */
        printf("no ramps on RGB rasters\n");
    }

    /*
     * modify the viewing transform so we can see the cube
     */
    xgl_object_get (ctx, XGL_CTX_VIEW_TRANS, &view_trans);

    xgl_transform_rotate (view_trans, 0.3,
              XGL_AXIS_Z, XGL_TRANS_POSTCONCAT);

    xgl_transform_rotate (view_trans, 0.3,
              XGL_AXIS_Y, XGL_TRANS_POSTCONCAT);

    xgl_transform_rotate (view_trans, 0.3,
              XGL_AXIS_X, XGL_TRANS_POSTCONCAT);

    /*
     * render a depth cued multipolyline

     */
    xgl_object_set (ctx, XGL_CTX_VDC_MAP, XGL_VDC_MAP_DEVICE, NULL);
    xgl_context_new_frame (ctx);
    xgl_object_set (ctx, XGL_CTX_VDC_MAP, XGL_VDC_MAP_ASPECT, NULL);

    xgl_object_set (ctx, XGL_3D_CTX_DEPTH_CUE_MODE,
                      XGL_DEPTH_CUE_LINEAR, NULL);

    if (ex_color_type == XGL_COLOR_INDEX)
            /* set color to highest value in ramp */
            ln_color.index = RAMP_SIZE - 1;
    else
            ln_color = white_color;
    xgl_object_set (ctx, XGL_CTX_LINE_COLOR, &ln_color, NULL);

    xgl_multipolyline (ctx, NULL, 1, &pl_3d);

    /* display color table */
    color_show (ras, -1);

    /* restore viewing transformation */
    xgl_transform_identity (view_trans);

    /* turn off depth cueing */
    xgl_object_set (ctx, XGL_3D_CTX_DEPTH_CUE_MODE,
                      XGL_DEPTH_CUE_OFF, NULL);
}

Color Mapping

Another way to map colors from one color space to another uses the Color Map attributes XGL_CMAP_COLOR_MAPPER, and XGL_CMAP_INVERSE_COLOR_MAPPER. These attributes point to functions available to the application programmer for manipulating colors, although typical color operations can be handled without them. The attribute XGL_CMAP_COLOR_MAPPER specifies a function that maps the color values from the device color space set by the application (with XGL_DEV_COLOR_TYPE) to the underlying real color space (as defined by XGL_DEV_REAL_COLOR_TYPE). XGL_CMAP_INVERSE_COLOR_MAPPER specifies a function that maps the values from the underlying real color space (set with XGL_DEV_REAL_COLOR_TYPE) to the device color space set by the
application (XGL_DEV_COLOR_TYPE). For information on writing an application-specific color mapper, see the XGL_CMAP_COLOR_MAPPER reference page in the XGL Reference Manual.

Color Cubes

In the RGB color model, XGL uses three colors: red, green, and blue, which are assigned to three perpendicular axes to form the color cube. With a red axis, a green axis, and a blue axis, the color cube can represent points in every possible color in three dimensions with three values. The RGB color cube is an additive color system where color is generated by mixing various colored light sources.
The corner of the cube where the axes originate is at 0,0,0, and the color is black. At the opposite corner, where red, green, and blue are at their brightest, the RGB values are 1,1,1, and the color is white. Figure 6-2 illustrates the RGB color cube.

グラフィック

Figure 6-2

The color cube is located in the color table associated with an XGL Color Map. The color cube converts RGB colors to indexed colors when the XGL Raster type is RGB and the underlying hardware is indexed. The attribute XGL_CMAP_COLOR_CUBE_SIZE sets the size of the color cube, specifying all three axes simultaneously. It is formatted as an array of three integers specifying the size of the red, green, and blue axes of the color cube, respectively.

Color Cube Example

The following example shows how color cubes can be created and used in an XGL application. The code in Code Example 6-3 is a part of a complete program that includes ex_utils.c and color_ccube_main.c, both of which are listed in Appendix B. To compile this program, type make color_ccube in the example program directory.
Code Example 6-3 Color Cube Example
/*
 * color_ccube.c
 */
#include <xview/xview.h>
#include <xgl/xgl.h>

#include "ex.h"

/* Geometric data used in examples */
/* a star polygon */
Xgl_pt_i2d           pts_i2d_pgon[6] = {
      0,   0, 200, 100,
      0, 100, 200,   0,
    100, 200,   0,   0
};

/*
 * an easy to use macro for setting up an Xgl RGB color data structure
 */
#define XGL_SET_RGB_COLOR(CLR, R, G, B)                         \
            CLR.rgb.r = R;                                      \
            CLR.rgb.g = G;                                      \
            CLR.rgb.b = B;

/*
 * a macro for setting up an Xgl point list data structure
 */
#define XGL_SET_PT_LIST_I2D(PL, PT_TYPE, BBOX, NUM_PTS, PTS_I2D) \
        PL.pt_type = PT_TYPE;                                   \
        PL.bbox = BBOX;                                         \
        PL.num_pts = NUM_PTS;                                   \
        PL.pts.i2d = PTS_I2D;

void
color_ccube (Xgl_object  ctx)
{
    Xgl_sgn32            i;
    Xgl_color_type       color_type;   /* color type of default raster
*/
    Xgl_object           ras;          /* default raster for ctx */
    Xgl_color            pgon_front_color;
    Xgl_pt_list          pl_2d;        /* polygon point list */

    /*
     * get raster object from context
     */
    xgl_object_get (ctx, XGL_CTX_DEVICE, &ras);

    /*
     * Ensure a raster of the correct color type.
     */
    xgl_object_get (ras, XGL_DEV_COLOR_TYPE, &color_type);
    if (color_type == XGL_COLOR_INDEX) {
        xgl_object_set (ctx, XGL_CTX_DEVICE, NULL, NULL);
        xgl_object_destroy(ras);
        ras = xgl_object_create(sys_st, XGL_WIN_RAS, &obj_desc,
                                XGL_DEV_COLOR_TYPE, XGL_COLOR_RGB,
                                NULL);
        xgl_object_set (ctx, XGL_CTX_DEVICE, ras, NULL);
    }

    xgl_context_new_frame (ctx);

    /*
     * draw some polygons to show the color cube at work
     */

    /*
     * draw a white star
     */
    XGL_SET_RGB_COLOR (pgon_front_color, 1.0, 1.0, 1.0);
    xgl_object_set (ctx,
                    XGL_CTX_SURF_FRONT_COLOR, &pgon_front_color,
                    NULL);
    XGL_SET_PT_LIST_I2D (pl_2d, XGL_PT_I2D, NULL, 6, pts_i2d_pgon);
    xgl_polygon (ctx, XGL_FACET_NONE, 0, 0, 1, &pl_2d);
    sleep (1);

    /*
     * draw a red star
     */
    XGL_SET_RGB_COLOR (pgon_front_color, 1.0, 0.0, 0.0);
    xgl_object_set (ctx,
                    XGL_CTX_SURF_FRONT_COLOR, &pgon_front_color,
                    NULL);
    XGL_SET_PT_LIST_I2D (pl_2d, XGL_PT_I2D, NULL, 6, pts_i2d_pgon);
    xgl_polygon (ctx, XGL_FACET_NONE, 0, 0, 1, &pl_2d);
    sleep (1);

    /*
     * draw a green star
     */
    XGL_SET_RGB_COLOR (pgon_front_color, 0.0, 1.0, 0.0);
    xgl_object_set (ctx,
                    XGL_CTX_SURF_FRONT_COLOR, &pgon_front_color,
                    NULL);
    XGL_SET_PT_LIST_I2D (pl_2d, XGL_PT_I2D, NULL, 6, pts_i2d_pgon);
    xgl_polygon (ctx, XGL_FACET_NONE, 0, 0, 1, &pl_2d);
    sleep (1);

    /*
     * draw a blue star
     */
    XGL_SET_RGB_COLOR (pgon_front_color, 0.0, 0.0, 1.0);
    xgl_object_set (ctx,
                    XGL_CTX_SURF_FRONT_COLOR, &pgon_front_color,
                    NULL);
    XGL_SET_PT_LIST_I2D (pl_2d, XGL_PT_I2D, NULL, 6, pts_i2d_pgon);
    xgl_polygon (ctx, XGL_FACET_NONE, 0, 0, 1, &pl_2d);
}

Dithering

Dithering mixes two or more colored pixels to approximate a given color on the screen. This means placing pixels of different colors next to each other so that from a distance, the colors blend together to make a different color. When dithering in monochrome, the effect desired is a shade (or shades) of gray, with brightness depending on the ratio of black (off) to white (on) pixels. The number of shades available depends on the number of pixels comprising a dither cell. The more pixels in a dither cell, the more shades of gray available. More pixels per cell means lower resolution, however, as each shade of gray is approximated by 2 . 2 or 4 . 4 pixels, etc. In color dithering, the dither cell is filled with one or more colors defined in the current Color Map. When viewed together, the colors approximate the desired color.
XGL provides several attributes for defining dither masks associated with a Color Map object. If an application's Raster color type is RGB and the underlying hardware is indexed, XGL will use a color cube and a dither mask to convert the application's RGB colors to the display's indexed colors. The read-only attribute XGL_CMAP_DITHER_MASK_N allows the application to get the dither mask size. The XGL Color Map dither mask must always be 8 x 8. To change the mask to 2 . 2 or 4 . 4, replicate the smaller mask into an 8 . 8 mask and then set it into the Color Map dither mask using the attribute XGL_CMAP_DITHER_MASK.

Using the Window System Color Map

The application can use the Xlib function calls to create a window system color map (not to be confused with the XGL Color Map object) for mapping colors from the application's color type to the hardware's color type. The X color map can be shared between XGL and the window system. To do this, an application should do the following:
  1. Create a window system color map using the Xlib call XCreateColormap.

  2. Get the color map name from the window system (the XID returned by the XCreateColormap call).

  3. Get the pixel mapping array returned by XAllocColorCells, XAllocColor, XAllocColorPlanes, or XAllocNamedColor.

  4. Set the XGL attribute XGL_CMAP_NAME to the window system color map name and set the color table size using XGL_CMAP_COLOR_TABLE_SIZE.

  1. Set XGL_WIN_RAS_PIXEL_MAPPING to the window system pixel mapping array. This tells the XGL application to use the pixel mapping from the window color map rather than from its own color map.

The application must ensure that the RGB values in the window system color map are correct. However, the application cannot query the contents of a window system produced color map using the XGL call xgl_object_get(). The application must manipulate the color map using window system calls.
When XGL creates its own Color Map (for example, the default Color Map object created when a new Window Raster object is created), XGL_CMAP_NAME reflects an internal X11 color map used by XGL and the window system. XGL implicitly uses the window system functions to create the X11 color map, associate it with an XGL Color Map object, and attach it to a Raster.
If the application sets XGL_CMAP_NAME, XGL_CMAP_COLOR_TABLE_SIZE and XGL_WIN_RAS_PIXEL_MAPPING should be set immediately afterward to ensure that the application's colors are properly mapped to the hardware indices. XGL also alters the background color attribute (see XSetWindow attributes) when the application sets XGL_CMAP_NAME. The application should not change the value of the background pixel after XGL has set it.
The default value of XGL_CMAP_NAME is the XID of the X color map XGL uses to allocate the color cells. The value can be the same as the XID returned by the macro DefaultColormap, or it can be the XID of a private X color map, depending on the availability of read/write color cells in the default X color map.
When allocating color cells from the window system, XGL does the following:
  1. Attempts to allocate read/write cells from the default X color map.

    If this fails, XGL uses XCreateColormap to create a private X color map and uses XAllocColorCells to allocate the read/write color cells from it.

  2. Converts the XGL color table associated with the color map object associated with the window raster object from RGB float values to XColor data structures.

  3. XGL uses XStoreColors to update the read/write cells allocated in the first step.

Color Map Double Buffering

Double buffering produces clean animation because rendering occurs in an hidden memory buffer while the contents of a second buffer are displayed. Once rendering is complete in the hidden buffer, its contents are switched with the contents of the buffer in view. The buffer that was in view is cleared, and a new scene is rendered into it. By quickly switching between buffers, an application can snap an image as a completely rendered scene into the display area. Rendering always occurs in the hidden buffer.
Some hardware has separate areas of memory specifically available for double buffering. Hardware that does not have such capabilities can use the plane enable mask in conjunction with XGL Color Maps for double buffering. The Raster's Color Map is toggled between two Color Maps working in tandem with two values for the Context's plane-enable mask. This is called color map double buffering.

Color Map Double Buffering Example

The following example, color_dbuf.c, uses color map double buffering to animate the rotation of a cube. The double buffering makes the motion smooth and visually appealing.
In this example, both buffers use two pixel bit planes. The bit planes define the bits of the color value associated with a pixel that will be used when displaying color on the device. For example, in an 8-bit frame buffer, where eight bits comprise each color value, any or all of the eight bits (or eight bit planes) can be enabled for displaying on the device.
Color map double buffering is implemented using the plane enable mask and two color maps. Two bits are used for each buffer, which results in a total of four colors. Only two (22) bits are used to specify colors in each buffer, and only a small number of colors can be used.
The benefits of color map double buffering need to be weighed against the cost of limiting color usage. Buffer 1 uses bit planes 1 and 2 (the first two bits of the pixel color), and buffer 2 uses planes 3 and 4. These are specified by setting the XGL attribute XGL_CTX_PLANE_MASK.
Rendering into buffer 1 is done when buffer 2 is displayed, and vice versa. Thus, when rendering into buffer 1, the Context's plane enable mask (XGL_CTX_PLANE_MASK) is set to 0xc (selecting the bits associated with buffer 2), which causes buffer 2 to be displayed. The mask is set to 0x3 when buffer 1 is displayed.
The application's indexing scheme should know whether XGL is drawing into buffer 1 or buffer 2, and should produce the same colors in either buffer. The following convention works well: when specifying colors, use the same index value for the same color in both buffers. If color 2 is used in the first buffer, it should be set in the second buffer as well. Color 2 is described as the index (2) in buffer 1 or (2 << 3) in buffer 2.
The code in Code Example 6-4 is a part of a complete program. The complete program includes ex_utils.c and color_main.c, both of which are listed in Appendix B. To compile this program, type make color in the example program directory. See Plates 4a and 4b for the two buffers used in this example.
Code Example 6-4 Color Map Double Buffering Example
/*
 * color_dbuf.c
 */

#include <xview/xview.h>
#include <xgl/xgl.h>

#include "ex.h"

extern Xgl_pt_list       pl_3d;
extern Xgl_object        dbufcmap1, dbufcmap2;

static Xgl_sgn32         current_buffer_is_buffer_1 = 1;

static void              switch_buffer(Xgl_object, Xgl_object);

void
color_dbuf (Xgl_object   ctx)
{
    Xgl_sgn32            i;
    double               angle;
    Xgl_object           ras;   /* raster associated with ctx */

    Xgl_object           cmap;  /* color map associated with
                                       * ras */
    Xgl_color            color[4];
    Xgl_color            ln_color;
    Xgl_object           view_trans;

    /*
     * if we are on an indexed raster then create two color maps to do
     * color map double buffering
     */
    if (ex_color_type == XGL_COLOR_INDEX) {
        /* get raster object from context */
        xgl_object_get (ctx, XGL_CTX_DEVICE, &ras);

        /*
         * get color map object from raster
         */
        xgl_object_get (ras, XGL_RAS_COLOR_MAP, &cmap);

        /*
         * if color map associated with raster isn't rampcmap then
          * put it into the raster
         */
        if (cmap != dbufcmap1 && cmap != dbufcmap2) {
            if (!dbufcmap1) {
            Xgl_color_list       clist;/* color table list */
            Xgl_color            colors[16];/* list of colors */

           /*
            * create color list
            */
           clist.start_index = 0;
           clist.length = 16;
           clist.colors = colors;

           /*
            * Set color maps to have 4 colors per color map:
             * black, green,blue, white
            */
           for (i = 0; i < 16; i++) {
            switch (i & 3) {
            case 0:
                colors[i].rgb.r = 0.0;
                colors[i].rgb.g = 0.0;
                colors[i].rgb.b = 0.0;
                break;

        case 1:
            colors[i].rgb.r = 0.0;
            colors[i].rgb.g = 1.0;
            colors[i].rgb.b = 0.0;
            break;
        case 2:
            colors[i].rgb.r = 0.0;
            colors[i].rgb.g = 0.0;
            colors[i].rgb.b = 1.0;
            break;
        case 3:
            colors[i].rgb.r = 1.0;
            colors[i].rgb.g = 1.0;
            colors[i].rgb.b = 1.0;
            break;
          }
        }

        /*
         * create buffer 1 color map object and set
         * the color table to our new colors
         */
        dbufcmap1 = xgl_object_create (sys_st, XGL_CMAP, NULL,
                       XGL_CMAP_COLOR_TABLE_SIZE, 16,
                       XGL_CMAP_COLOR_TABLE, &clist,
                       NULL);
    }

    if (!dbufcmap2) {
        Xgl_color_list       clist;/* color table list */
        Xgl_color            colors[16];/* list of colors */

        /*
         * create color list
         */
        clist.start_index = 0;
        clist.length = 16;
        clist.colors = colors;

        /*
         * Set color maps to have 4 colors per
         * color map:  black, green,blue, white
         */
        for (i = 0; i < 16; i++) {
          switch (i >> 2) {

              case 0:
                colors[i].rgb.r = 0.0;
                colors[i].rgb.g = 0.0;
                colors[i].rgb.b = 0.0;
                break;
              case 1:
                colors[i].rgb.r = 0.0;
                colors[i].rgb.g = 1.0;
                colors[i].rgb.b = 0.0;
                break;
              case 2:
                colors[i].rgb.r = 0.0;
                colors[i].rgb.g = 0.0;
                colors[i].rgb.b = 1.0;
                break;
              case 3:
                colors[i].rgb.r = 1.0;
                colors[i].rgb.g = 1.0;
                colors[i].rgb.b = 1.0;
                break;
              }
           }
           /*
            * create buffer 2 color map object and set
             * the color table to our new colors
            */
           dbufcmap2 = xgl_object_create (sys_st, XGL_CMAP, NULL,
                           XGL_CMAP_COLOR_TABLE_SIZE, 16,
                           XGL_CMAP_COLOR_TABLE, &clist,
                           NULL);
          }
        }

        color[0].index = 0;
        color[1].index = (1 << 2) | 1;
        color[2].index = (2 << 2) | 2;
        color[3].index = (3 << 2) | 3;

        ln_color = color[3];
        xgl_object_set (ctx, XGL_CTX_LINE_COLOR, &ln_color, NULL);
    }
    else {
        /* RGB raster so just set color; no double buffering */
        printf("no color map double buffering on RGB rasters\n");
        ln_color = white_color;
        xgl_object_set (ctx, XGL_CTX_LINE_COLOR, &ln_color, NULL);

    }

    xgl_object_set (ctx, XGL_CTX_VDC_MAP, XGL_VDC_MAP_ASPECT, NULL);

    /*
     * modify the viewing transform so we can see the cube
     */
    xgl_object_get (ctx, XGL_CTX_VIEW_TRANS, &view_trans);

    i = 0;
    angle = 0.;
    while (angle <= 6.28) {

   switch_buffer (ctx, ras);
   /*
    * clear raster after waiting for retrace
    */
   xgl_object_set (ctx, XGL_CTX_NEW_FRAME_ACTION,
            XGL_CTX_NEW_FRAME_VRETRACE | XGL_CTX_NEW_FRAME_CLEAR,
            NULL);
   xgl_object_set (ctx, XGL_CTX_VDC_MAP, XGL_VDC_MAP_DEVICE, NULL);
   xgl_context_new_frame (ctx);
   xgl_object_set (ctx, XGL_CTX_VDC_MAP, XGL_VDC_MAP_ASPECT, NULL);

   /*
    * rotate for animation
    */
   xgl_transform_rotate (view_trans, angle,
                  XGL_AXIS_Z, XGL_TRANS_REPLACE);

   xgl_transform_rotate (view_trans, angle,
                  XGL_AXIS_Y, XGL_TRANS_POSTCONCAT);

   xgl_transform_rotate (view_trans, angle,
                  XGL_AXIS_X, XGL_TRANS_POSTCONCAT);

   xgl_multipolyline (ctx, NULL, 1, &pl_3d);

   angle += .01;
 }

    xgl_transform_identity (view_trans);
    if (ex_color_type == XGL_COLOR_INDEX)
        xgl_object_set (ctx, XGL_CTX_PLANE_MASK, 0xff, NULL);

    color_show (ras, -1);

}

static
void
switch_buffer (
    Xgl_object           ctx,
    Xgl_object           ras)
{
    if (ex_color_type == XGL_COLOR_INDEX) {
        if (current_buffer_is_buffer_1) {
           xgl_object_set (ras, XGL_RAS_COLOR_MAP, dbufcmap1, NULL);
           xgl_object_set (ctx, XGL_CTX_PLANE_MASK, 0xc, NULL);
        }
        else {
           xgl_object_set (ras, XGL_RAS_COLOR_MAP, dbufcmap2, NULL);
           xgl_object_set (ctx, XGL_CTX_PLANE_MASK, 0x3, NULL);
        }
        current_buffer_is_buffer_1 ^= TRUE;
    }
}