/* glib3.c
 ○ Glib_math_coordinate=1 が default です. math_coordinate を使わない場合は,
      glib_no_math_coordinate() を呼び出す.

 ○ プログラムの最後に, getchar(); 等を書いておかないと実行終了したらすぐ画面が消えます.
 ○ oscillator-g3.c が利用例です.
 ○ glib_line, glib_set_pixel にはかならず色パラメータが必要です.
%%Ref: misc-2017/12/keisan-1/win13.c2
*/

/* The original file is at Texts/text-92/glib.c, Texts/text-99/Joho/glib.c */
/*  
    どうやって, 文字を書くの? とか どうやって マウスの event を取り出すの?
    とか疑問におもったときは, 
    参考文献
    (1) http://www.wakhok.ac.jp/JJ/JJ.html   X window 概論
    (2) Xlib のマニュアル.  man XDrawLine, 等

*/
/* old unix: cc -DTEST -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 glib3.c */
/* unix: gcc -DTEST glib3.c -lX11 */
/* Mac: cc -DTEST -I/opt/X11/include -L/opt/X11/lib glib3.c -lX11  */
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>

/* prototypes */
void gopen();
void glib_open();
void gclose();
void gFlush();
void moveto(int x,int y);
void lineto(int x,int y,int color);
void setpixel(int x,int y,int color);
void glib_window(double xmin,double ymin, double xmax, double ymax);
void glib_line(double x0,double y0, double x1, double y1,int color);
void glib_putpixel(double x0,double y0,int color);
void glib_flush();
void glib_clear();
void glib_set_frame_no(int n);
void glib_init_frame_no(int n);
void glib_close();
void glib_cgif_pen_up();
void glib_set_color(int color);
void glib_no_math_coordinate(void);

#ifdef TEST
int main() {
  int k;
  gopen();
//  printf("Type in enter.\n"); getchar();
  for (k=10; k<=500; k++) {
    setpixel(k,k,0xff00ff);
  }
  moveto(-100,100);
  lineto(1000,100,0xff00);
  for (k=10; k<=300; k += 20) {
    moveto(0,0);
    lineto(100,2*k,k*0x100);
  }
  glib_flush();
  glib_flush();
  getchar();
  printf("Type in enter to finish.\n"); getchar();
  gclose();
  return(0);
}
  
#endif


double Glib_xmin, Glib_xmax, Glib_ymin, Glib_ymax;

/* -------------------- main code of glib.c ---------------- */
#define XSIZE 600
#define YSIZE 600

/* global variables */
Display *glib_d;
Window glib_w;
GC glib_gc;
XSetWindowAttributes glib_a;
Colormap glib_cmap;
int glib_no_mathCoordinate=0;

static int glib_x = 0;
static int glib_y = 0;

/* functions exported */
void gopen() {
  static int already_open=0;
  XColor back;
  if (already_open) return;
  already_open=1;
  glib_d = XOpenDisplay(NULL);

  glib_cmap = DefaultColormap(glib_d,0);
  back.red=0;  back.green=20000;  back.blue=0;
  XAllocColor( glib_d, glib_cmap, &back );

  glib_w = XCreateSimpleWindow(glib_d,DefaultRootWindow(glib_d),0,0,
			  XSIZE,YSIZE,1,BlackPixel(glib_d,0),WhitePixel(glib_d,0));
  /*  xsize, ysize, border color, border, background */

  // No window frames, ...
  //glib_a.override_redirect = 1;
  //XChangeWindowAttributes(glib_d,glib_w,CWOverrideRedirect, &glib_a); 


  glib_gc = XCreateGC(glib_d,glib_w,(unsigned long)NULL,NULL);
  /*                0 : default of mask, 0 : default XGCvalues * */

  XStoreName(glib_d,glib_w,"glib3");
  XMapWindow(glib_d,glib_w);
  XFlush(glib_d);
  // getchar();
  /* gcc -dM dummy.c to list predefined macros */
  /* bug on Mac; we need the following lines. */
#ifdef __APPLE__
  sleep(4);
#endif
  /*
  XSetForeground(glib_d,glib_gc,back.pixel);
  XFlush(glib_d);
  XFillRectangle(glib_d,glib_w,glib_gc,0,10,50,50);
  XFlush(glib_d);
  */
  /* intialize line attributes */
  XSetLineAttributes(glib_d,glib_gc,1,LineSolid,CapButt,JoinMiter);
}

void gclose() {
  XFlush(glib_d);
}

void gFlush() {
  XFlush(glib_d);
}


void moveto(x,y)
int x,y;
{
  glib_x = x;
  glib_y = y;
}

void lineto(x,y,color)
int x,y,color;
{
  glib_set_color(color);
  XDrawLine(glib_d,glib_w,glib_gc,glib_x,glib_y,x,y);
  glib_x = x; glib_y = y;
}

void setpixel(x,y,color)
int x,y,color;
{
  glib_set_color(color);
  XDrawPoint(glib_d,glib_w,glib_gc,x,y);
}


void glib_window(double xmin,double ymin, double xmax, double ymax) {
  Glib_xmin = xmin;
  Glib_ymin = ymin;
  Glib_xmax = xmax;
  Glib_ymax = ymax; 
  gopen();
}

#define P(x)  (((x-Glib_xmin)/(Glib_xmax-Glib_xmin))*(double)XSIZE)
#define Q(y)  ((double)YSIZE-((y-Glib_ymin)/(Glib_ymax-Glib_ymin))*(double)YSIZE)
void glib_line(double x0,double y0, double x1, double y1,int color) {
  int p0,q0,p1,q1;
  p0 = (int) P(x0);
  q0 = (int) Q(y0);
  p1 = (int) P(x1);
  q1 = (int) Q(y1);
  if (glib_no_mathCoordinate) {
    q0=YSIZE-q0;
    q1=YSIZE-q1;
  }
  moveto(p0,q0);
  lineto(p1,q1,color);
}

void glib_putpixel(double x0,double y0,int color) {
  int p0,q0;
  p0 = (int) P(x0);
  q0 = (int) Q(y0);
  if (glib_no_mathCoordinate) q0=YSIZE-q0;
  setpixel(p0,q0,color);  
}

void glib_flush() {
  gFlush();
}


void glib_clear() {
  XClearArea(glib_d,glib_w,0,0,XSIZE,YSIZE,False);
}

void glib_set_frame_no(int n) {
  /* not implemented */
}

void glib_init_frame_no(int n) {
  /* not implemented */
}

void glib_close() {
  gclose();
}

void glib_cgif_pen_up() {
  /* do nothing */
}

void glib_set_color(int color) {
  static XColor mycolor;
  static int prev_color=0;
  int r,g,b;
  if (color == prev_color) return;
  else prev_color=color;
  // 24 bit color;
  r = (color & 0xff0000) >> 16;
  g = (color & 0xff00) >> 8;
  b = (color & 0xff);
  mycolor.red = r << 8;
  mycolor.green = g << 8;
  mycolor.blue = b << 8;
  XAllocColor(glib_d,glib_cmap,&mycolor);
  XSetForeground(glib_d,glib_gc,mycolor.pixel);
  return;
}

void glib_open() {
  gopen();
}

void glib_no_math_coordinate() {
  glib_no_mathCoordinate=1;
}
