/*-------------------------------------------------------------------------*/
/*  J3W ver 6.42  3D Animation Kit                                         */
/*  scrnx.cpp     10/22/2000                                               */
/*  Copyright (C) 1997-2000 Jun Mizutani < mizutani.jun@nifty.ne.jp>       */
/*                      All rights reserved.                               */
/*                                                                         */
/*   This file is part of the J3W 3D Animation Kit, and is covered under   */
/*  the terms of the GNU General Public License, version 2. This file has  */
/*  NO WARRANTY. See file COPYING for copyright details.                   */
/*                                                                         */
/*-------------------------------------------------------------------------*/

#ifdef WS
#include <stdio.h>
#include <WSCcolorSet.h>
#include <WSDmwindowDev.h>
#else //WS
#include <iostream.h>
#include <X11/Xatom.h>
#endif //WS
#include "scrnx.h"
#include "pal256.h"

ScrnX::ScrnX() : TScreen()
{
    range_y = 480;
    range_x = 640;

    width = 640;
    height = 480;

    BG_Color = 255;
    max_color = 256;
    ncol = max_color;
    mode = 0;
#ifdef WS
    _mdev = NULL;
    _dev = NULL;
    _whiteid = -1;
    _blackid = -1;
    int i;
    for(i=0; i<256;i++){
      colors[i] = NULL;
    }
#else //WS
    d = 0;
#endif //WS
    SetDefaultPalette();
}

ScrnX::~ScrnX() {
#ifndef WS
    if (d) {
        XFreePixmap(d, p);
        XFreeColormap(d, cmap);
        XUnloadFont(d, f);
        XFreeGC(d, gc);
        XDestroyWindow(d, w);
        XCloseDisplay(d);
        d = 0;
    }
#endif //WS
}

int  ScrnX::set_mode(int m) {
    if (m == 1) {
#ifndef WS
      if (mode == 0) OpenX();
#endif //WS
    } else if (m == 2) mode = 2;
    else restore_mode();
    mode = m;
    return 1;
}
#ifdef WS
void ScrnX::setDev(WSDdev* dev){
  _dev = dev;
  if (_mdev == NULL){
    _mdev = WSDmwindowDev::getNewInstance();
    _mdev->createPixmap(width,height);
  }
  SetColorMap();
}
long ScrnX::beginDraw(){
  if (_mdev == NULL){
    return WS_ERR;
  }
//printf("ScrnX::beginDraw()..\n");
  return _mdev->beginDraw(0,0,width,height);
}
long ScrnX::endDraw(){
  if (_mdev == NULL){
    return WS_ERR;
  }
//printf("ScrnX::endDraw()..\n");
  return _mdev->endDraw();
}

#else //WS
void ScrnX::OpenX()
{
    int depth;

    if(!(d = XOpenDisplay(NULL))) {
        cerr << "Can't open Display.\n";
        exit(1);
    }

    int scr = XDefaultScreen(d);
    if((depth = XDefaultDepth(d,scr)) < 8) {
        cerr << "Display needs to support 8 bit color\n";
        exit(1);
    }
    Visual *vis = XDefaultVisual(d, scr);

    black = BlackPixel (d, 0);
    white = WhitePixel (d, 0);

    w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0,
                              width, height, 1, black, white );

    XSelectInput(d, w, KeymapStateMask | KeyPressMask);

    XStoreName(d, w, "J3W");
    XMapWindow (d, w);

    p = XCreatePixmap( d, w, width, height, DefaultDepth(d, 0) );
    gc  = XCreateGC (d, p, 0, 0);

    f = XLoadFont(d, "-*-courier-bold-r-*-*-12-*-*-*-*-*-*-*");
    XSetFont (d, gc, f);
    XSetForeground (d, gc, white);

    XFillRectangle (d, p, gc, 0, 0, width, height);

    SetColorMap(vis);
    XSetWindowColormap(d, w, cmap);
}
#endif //WS
void ScrnX::SetPaletteEntry(int n, int r , int g, int b)
{
#ifdef WS
    if (mode){
      char buffer[64];
      if (r > 255|| g > 255 || b > 255){
        sprintf(buffer,"#%04x%04x%04x",r,g,b);
      }else{
        sprintf(buffer,"#%02x%02x%02x",r,g,b);
      }
      colors[n] = WSGIappColorSet()->getColor(buffer);
//printf("ScrnX::SetPaletteEntry %d rgb=%d %d %d %s\n",n,r,g,b,buffer);
    }
#else
    if (mode) {
        col[n].pixel = n;
        col[n].red = r;
        col[n].green = g;
        col[n].blue = b;
        col[n].flags = DoRed | DoGreen | DoBlue;
        if (color_mode == PSEUDOCOLOR) {
            XStoreColor(d, cmap, &col[n]);
            XInstallColormap(d, cmap);
        } else {
            XAllocColor(d,cmap,&col[n]);
        }
    }
#endif
}

void ScrnX::UpdatePalette()
{
#ifdef WS
    for (int i=0; i<(ncol-SYSCOLOR); i++) {
        SetPaletteEntry(i+SYSCOLOR , MyPalette[i].r, MyPalette[i].g,
                         MyPalette[i].b);
    }
#else //WS
    for (int i=0; i<(ncol-SYSCOLOR); i++) {
        SetPaletteEntry(i+SYSCOLOR , MyPalette[i].r << 8, MyPalette[i].g << 8,
                         MyPalette[i].b << 8);
    }
#endif //WS
}
#ifdef WS
void ScrnX::SetColorMap()
{
  int i;
  for (i=0; i<(ncol-SYSCOLOR); i++) {
    char buffer[64];
    sprintf(buffer,"#%02x%02x%02x", MyPalette[i].r, MyPalette[i].g,
                                    MyPalette[i].b);
    colors[i+SYSCOLOR] = WSGIappColorSet()->getColor(buffer);
//printf("SetColorMap %d %s\n",i,buffer);
  }
}
#else //WS
Display* ScrnX::GetDisplay()
{
    return d;
}

Window* ScrnX::GetWindow()
{
    return &w;
}
void ScrnX::SetupColorInfo()
{
   XVisualInfo v_temp, *vi;
   long mask;
   int n;

   mask = VisualScreenMask | VisualDepthMask | VisualClassMask | VisualIDMask;
   v_temp.screen = 0;
   v_temp.depth =  DefaultDepth(d, 0);
   v_temp.c_class = DefaultVisual(d, 0)->c_class;
   v_temp.visualid = DefaultVisual(d ,0)->visualid;

   vi = XGetVisualInfo(d, mask, &v_temp, &n);

   rshift = 0;
   gshift = 0;
   bshift = 0;
   rbits = 0;
   gbits = 0;
   bbits = 0;
   unsigned long rmask = vi->red_mask;
   unsigned long gmask = vi->green_mask;
   unsigned long bmask = vi->blue_mask;
   while ((rmask & 1)==0) { rshift++; rmask >>= 1; }
   while (rmask & 1) { rbits++; rmask >>= 1; }
   while ((gmask & 1)==0) { gshift++; gmask >>= 1; }
   while (gmask & 1) { gbits++; gmask >>= 1; }
   while ((bmask & 1)==0) { bshift++; bmask >>= 1; }
   while (bmask & 1) { bbits++; bmask >>= 1; }

   XFree(vi);
}

void ScrnX::SetColorMap(Visual* vis)
{
    unsigned long planes[1], pixel[ncol];
    Colormap dcm;

    switch( vis->c_class ) {
    case StaticColor:
    case TrueColor:
        color_mode = TRUECOLOR;
        SetupColorInfo();
        cmap = DefaultColormap(d, 0);
        for (int i=0; i<(ncol-SYSCOLOR); i++) {
            col[i+SYSCOLOR].red   = MyPalette[i].r << 8;
            col[i+SYSCOLOR].green = MyPalette[i].g << 8;
            col[i+SYSCOLOR].blue  = MyPalette[i].b << 8;
            col[i+SYSCOLOR].flags = DoRed | DoGreen | DoBlue;
            XAllocColor(d,cmap,&col[i+SYSCOLOR]);
        }
        break;

    case PseudoColor:
    case DirectColor:
        color_mode = PSEUDOCOLOR;

        dcm = DefaultColormap(d,0);
        cmap = XCreateColormap(d, w, vis, AllocNone);
        while( ncol > 1) {
            if (XAllocColorCells(d, cmap, 1, planes, 0, pixel, ncol)) break;
            cerr << "Error : Try to allocate " << ncol << " colors.\n";
            ncol--;
        }
        for(int i=0; i<SYSCOLOR; i++){
            col[i].pixel = i;
            XQueryColor(d, dcm, &col[i]);

        }
        for (int i=0; i<(ncol-SYSCOLOR); i++) {
            col[i+SYSCOLOR].red   = MyPalette[i].r << 8;
            col[i+SYSCOLOR].green = MyPalette[i].g << 8;
            col[i+SYSCOLOR].blue  = MyPalette[i].b << 8;
            col[i+SYSCOLOR].flags = DoRed | DoGreen | DoBlue;
            col[i+SYSCOLOR].pixel = pixel[i+SYSCOLOR];
        }

        XStoreColors(d, cmap, col, ncol);
        XInstallColormap(d, cmap);
        break;
    }
}
#endif //WS
void ScrnX::restore_mode()
{
#ifndef WS
    if (d) {
        XFreePixmap(d, p);
        XFreeColormap(d, cmap);
        XUnloadFont(d, f);
        XFreeGC(d, gc);
        XDestroyWindow(d, w);
        XCloseDisplay(d);
        d = 0;
    }
#endif //WS
    mode = 0;
}

void ScrnX::update() {
#ifdef WS
    if (_mdev != NULL && _dev != NULL){
      _mdev->copyToWindow(_dev,0,0,width,height,0,0);
      _mdev->beginDraw(0,0,width,height);
      _mdev->setForeColor(colors[BG_Color]);
      _mdev->drawFillRect(0,0,width,height);
      _mdev->endDraw();
    }
#else //WS
    XCopyArea(d, p, w, gc, 0, 0, width, height, 0, 0);
    XFlush (d);

    XSetForeground (d, gc, col[BG_Color].pixel);
    XFillRectangle (d, p, gc, 0, 0, width, height);
    XSync(d, 0);
#endif //WS
}

void ScrnX::clear() {
#ifdef WS
//printf("ScrnX::clear()..\n");
  if (_mdev != NULL){
    if (_whiteid == -1){
      _whiteid = WSGIappColorSet()->getColorNo("#ffffff");
    }
//    _mdev->beginDraw(0,0,width,height,True,False);
    _mdev->setForeColor(_whiteid);
    _mdev->drawRect(0,0,width,height);
//    _mdev->endDraw();
  }
#else //WS
    XSetForeground (d, gc, white );
    XFillRectangle (d, p, gc, 0, 0, width, height);
#endif //WS
}

int  ScrnX::line(Vector2D p1, Vector2D p2, int color)
{
#ifdef WS
//printf("ScrnX::line...color=%d\n",color);
  if (_mdev == NULL){
    return 1;
  }
  _mdev->setForeColor(colors[color]);
  _mdev->drawLine(p1.x,p1.y,p2.x,p2.y);
#else //WS
    XSetForeground (d, gc, col[color].pixel);
    XDrawLine(d, p, gc, p1.x, p1.y, p2.x, p2.y);
#endif //WS
    return 1;
}

int  ScrnX::line_rgb(Vector2D p1, Vector2D p2, int r, int g, int b)
{
#ifdef WS
//printf("ScrnX::line_rgb...%d %d %d\n",r,g,b);
  if (_mdev == NULL){
    return 1;
  }
//TEST
//  _mdev->setForeColor(colors[color]);
  _mdev->drawLine(p1.x,p1.y,p2.x,p2.y);

#else //WS
    unsigned long pixel;

    pixel = (((r>>(8-rbits)) << rshift)
            +((g>>(8-gbits)) << gshift)
            +((b>>(8-bbits)) << bshift));

    XSetForeground (d, gc, pixel);
    XDrawLine(d, p, gc, p1.x, p1.y, p2.x, p2.y);
#endif //WS
    return 1;
}

int  ScrnX::point(Vector2D p, int color)
{
#ifdef WS
//printf("ScrnX::point...%d\n",color);
#else //WS
    XPoint xp;

    xp.x = p.x; xp.y = p.y;
    XSetForeground (d, gc, col[color].pixel);

#endif //WS
    return 1;
}

int ScrnX::polygon(Vector2D *vp, int vn, int color)
{
#ifdef WS
//printf("ScrnX::polygon col=%d 0x%x\n",color,color);
    WSCpoint pt[20];

    if (mode == 2) {
        int i;
        for(i = 0 ; i < vn -1; i++)
          line(vp[i], vp[i+1], color);
        line(vp[vn-1], vp[0], color);
    } else {

        if (vn >= 20) return 0;
        int i;
        for(i=0; i<vn;i++) {
            pt[i].x = vp[i].x;
            pt[i].y = vp[i].y;
//printf("%d,%d - ",vp[i].x,vp[i].y);
        }
//printf("\n");
        if (colors[color] == NULL){
//printf("ScrnX::polygon err return\n");
          return 1;
        }
//printf("ScrnX::polygon color=%s %d\n",colors[color]->getColorName(),color);
        _mdev->setForeColor(colors[color]);
        _mdev->drawFillPoly(pt,vn);
    }
#else //WS
    XPoint xp[20];

    if (mode == 2) {
        for(int i = 0 ; i < vn -1; i++)
          line(vp[i], vp[i+1], color);
        line(vp[vn-1], vp[0], color);
    } else {

        if (vn >= 20) return 0;
        for( int i=0; i<vn;i++) {
            xp[i].x = vp[i].x;
            xp[i].y = vp[i].y;
        }

        XSetForeground (d, gc, col[color].pixel);
        XFillPolygon(d, p, gc, (XPoint *)xp, vn, Convex, CoordModeOrigin);
    }
#endif //WS
    return 1;
}

int ScrnX::polygon_rgb(Vector2D *vp, int vn, int r, int g, int b)
{
#ifdef WS
//printf("ScrnX::polycon_rgb %d %d %d\n",r,g,b);
#else //WS
    XPoint xp[24];
    unsigned long pixel;

    if (mode == 2) {
        for(int i = 0 ; i < vn -1; i++)
          line_rgb(vp[i], vp[i+1], r, g, b);
        line_rgb(vp[vn-1], vp[0], r, g, b);
    } else {
        if (vn >= 24) return 0;
        for( int i=0; i<vn;i++) {
            xp[i].x = vp[i].x;
            xp[i].y = vp[i].y;
        }

        pixel = (((r>>(8-rbits)) << rshift)
                +((g>>(8-gbits)) << gshift)
                +((b>>(8-bbits)) << bshift));

        XSetForeground (d, gc, pixel);
        XFillPolygon(d, p, gc, (XPoint *)xp, vn, Convex, CoordModeOrigin);
    }
#endif //WS
    return 1;
}

int  ScrnX::write_text(int x, int y,int color, char* text)
{
#ifdef WS
    char wstr[81];
    _mdev->setForeColor(colors[color]);
    for(int j=0; j<25; j++) {
      int i;
      for(i=0; i<80; i++) wstr[i] = text[j*80+i];
      wstr[80] = 0;
      int k = 79;
      while (wstr[k] == ' ' && k >= 0) wstr[k--] = 0;
      if ( k >= 0 ){
        WSCstring tmp(wstr);
        _mdev->drawString(x, y+(j+1)*19, 2000,50,&tmp,0,WS_LEFT_TOP,-1,0);
      }
    }
#else //WS
    char wstr[81];

    XSetForeground (d, gc,  col[color].pixel);
    for(int j=0; j<25; j++) {
        for(int i=0; i<80; i++) wstr[i] = text[j*80+i];
        wstr[80] = 0;
        int i = 79;
        while (wstr[i] == ' ' && i >= 0) wstr[i--] = 0;
        if ( i >= 0 )
            XDrawString(d, p, gc, x, y+(j+1)*19, wstr, i+1);
    }
#endif //WS
    return 1;
}
