/* colorw.c   color wheel based on phase angle                             */
/*            press any key to kill program                                */
/*            run program  colormap after this one to see values of colors */
/*            1/1/97 JSS initial version                                   */
/*            tested on OpenVMS, SunOS, Exceed on PC                       */

/* may be compiled and linked using    gcc -o colorw colorw.c -lX11 -lm    */

#define FUNCPROTO 1

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>      

/******************** X setup ********************/

static Display *display;  /* display */
static Window window1;    /* window */
static GC gc;             /* graphics context */
static Screen *screen;    /* screen pointer */
static int screen_num;    /* screen number */
static XColor cell;       /* .pixel, .red, .green, .blue .flags */
static Colormap colormap; /* default colormap */
static int x_res = 320;         /* 640; */
static int y_res = 320;         /* 640; */
static double center_x = 160.0; /* 320.0 */
static double center_y = 160.0; /* 320.0 */
static double radius_1 = 80.0;  /* 160.0 */
static double radius_2 = 160.0; /* 320.0 */
static int linewidth = 5;       /* 10 */

/* function prototypes of internal functions */

static void doInitialize(void);
static void doExpose(XEvent *eventP);
static void doHandleEvents(void);


/************** The main program *************************/
int main(void)
{          
    doInitialize();      /* set up windows        */
    doHandleEvents();    /* go into event loop    */
    return 0;            /* never comes back here */
}                                        


/***************** doInitialize **************************/
static void doInitialize(void)
{
    int window1W = x_res;
    int window1H = y_res;
    int window1X = 100;     /* just a arbitrary placement position, */
    int window1Y = 200;     /* the window manager may ignore this */
    XGCValues xgcv ;
    XSetWindowAttributes xswa;
                   

    display = XOpenDisplay(0);	
    if (!display){
        printf("Display not opened, check DISPLAY or DECW$DISPLAY!\n");
        exit(-1);
    }
    screen = XDefaultScreenOfDisplay(display);

    screen_num = DefaultScreen(display);

    colormap = DefaultColormap(display, screen_num);

    /* Create the window1 window */

    xswa.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask
                    | KeyPressMask | StructureNotifyMask;

    xswa.background_pixel = XWhitePixelOfScreen(screen);

    window1 = XCreateWindow(display, XRootWindowOfScreen(screen),
	window1X, window1Y, window1W, window1H, 0,
	XDefaultDepthOfScreen(screen), InputOutput,
	XDefaultVisualOfScreen(screen), CWEventMask | CWBackPixel, &xswa);

    
    /* Create graphics context. */

    xgcv.foreground = XBlackPixelOfScreen(screen);
    xgcv.background = XWhitePixelOfScreen(screen);
    gc = XCreateGC(display, window1, GCForeground | GCBackground, &xgcv);

    XStoreName(display, window1, "Color Window");

    XMapWindow(display, window1);

} /* end doInitialize */


/****************** doHandleEvents ***********************/
static void doHandleEvents(void)
{
    XEvent event;

    for ( ; ; ) {
	XNextEvent(display, &event);
	switch (event.type) { 
            case Expose:        
                  if(event.xexpose.window != window1) break;
                  doExpose(&event);
                  break;
            case KeyPress:
                  if(event.xkey.window != window1) break;
                  exit(0);
        }
    }                                           
} /* end doHandleEvents */


#define PI 3.1415983
#define dabs(x) ((x>=0.0)?x:(-x))
#define dmax(x,y) ((x)>(y)?(x):(y))

/***************do Expose   Handle expose event *********/
static void doExpose(XEvent *eventP)
{
  int x1, x2, y1, y2;
  double A, AA, AAA; /* temporaries */
  double R, G, B;    /* red, green, blue intensities computer */
  XColor cell;       /* used to get color allocated in colormap and get pixel*/
  int status;        /* XAllocColor may fail if all slots are used */

  XClearWindow(display, window1);
  XSetLineAttributes(display, gc, linewidth, LineSolid, CapRound, JoinRound);

  A = -1.0;
  while(A < 1.0)  /* walk the angle in bams around the circle */
  {
    /* A = arctan(Y, X)/PI   for normalized angle from X-Y plot        */
    /* get double R,G,B  R==1 at A==0, G==1 at A==2/3, B==1 at A==-2/3 */
    R = 1.0 - dabs(A);
    AA = A - 2.0/3.0;
    if(AA < -1.0) AA = 2.0+AA;
    G = 1.0 - dabs(AA);
    AA = A + 2.0/3.0;
    if(AA > 1.0) AA = 2.0-AA;
    B = 1.0 - dabs(AA);

    /* boost low end and normalize (this brightens colors) */
    R = R+0.2;
    G = G+0.2;
    B = B+0.2;
    AAA = dmax(R, G);
    AAA = dmax(AAA, B);
    R = R/AAA;
    G = G/AAA;
    B = B/AAA;
    

    /* set cell colors */
    cell.red = 65535.0 * R;
    cell.green = 65535.0 * G;
    cell.blue = 65535.0 * B;
    cell.flags = DoRed | DoGreen | DoBlue;
    status = XAllocColor(display, colormap, &cell);
    if(status==0)printf("could not allocate color at %g \n", A);
    XSetForeground(display, gc, cell.pixel);

    /* compute line ends */
    x1 = radius_1 * cos(A * PI) + center_x;
    y1 = radius_1 * sin(A * PI) + center_y;
    x2 = radius_2 * cos(A * PI) + center_x;
    y2 = radius_2 * sin(A * PI) + center_y;
    XDrawLine(display, window1, gc, x1, y1, x2, y2);
    A = A + 0.02;  /* 100 lines */
  }
}   /* end doExpose, one draw of screen */


