//===============================================================
// vbaseGLCanvas - a basic GL window canvas for drawing
//
// Copyright (C) 1995-1998  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vbglcnv.h>          // our header
#include <v/vapp.h>
#include <v/vos2.h>
#include <v/vwindow.h>
#include <stdlib.h>

// OpenGL init
  int vBaseGLCanvasPane::_pixelFormat = 0;
  int vBaseGLCanvasPane::_doubleBuffer = 0;   // if we have double buffering
  unsigned int vBaseGLCanvasPane::_vGLmode = 0;

//================>>> vBaseGLCanvasPane::vBaseGLCanvasPane <<<========================
  vBaseGLCanvasPane::vBaseGLCanvasPane(unsigned int vGLmode,
    PaneType pt) : vCanvasPane(pt)
  {
    SysDebug(Constructor,"vBaseGLCanvasPane::vBaseGLCanvasPane() constructor\n")
    const unsigned int defGLmode = (vGL_RGB | vGL_DoubleBuffer | vGL_Depth);
    _vGLmode = ((vGLmode == vGL_Default) ? defGLmode : vGLmode);
    _hDC = 0;          // PS is not needed for Direct OpenGL
    _hGLRC = 0;        // handle to OPENGL display context
    _hPalette = 0;     // index mode (palette) not supported in OS/2
    _hab = theApp->AppHab();
  }

//================>>> vBaseGLCanvasPane::~vBaseGLCanvasPane <<<===================
  vBaseGLCanvasPane::~vBaseGLCanvasPane()
  {
    SysDebug(Destructor,"vBaseGLCanvasPane::~vBaseGLCanvasPane() destructor\n")

    // OpenGL: finish OpenGL rendering
    if (_hDC)
      WinReleasePS(_hDC);

    if (_hGLRC)
    {
      pglMakeCurrent(_hab, 0, 0);
      pglDestroyContext(_hab, _hGLRC);
    }

    if (_hPalette)
      GpiDeletePalette(_hPalette);
  }

//==================>>> vBaseGLCanvasPane::initialize <<<==========================
  void vBaseGLCanvasPane::initialize(vWindow* pWindow, HWND pWidget)
  {
    vCanvasPane::initialize(pWindow, pWidget);  // init std canvas
    // the initialize will call CreateDC, which will normally create
    // a PM presentation space.
    //
    // If we use the Direct OPENGL context we do not need a PS.
    // The downside is no Gpi functions will be available to use in
    // the OPENGL canvas.  I think this is also true of the X and windoze
    // ports so will be okay.
    // Will need to override CreateDC so that it does not create a PS.

    // first we need to check to see if OpenGL is installed on system
    // If not, we punt with error message

    if (!pglQueryCapability(_hab))
    {
      UserDebug(WindowEvents,"No OpenGL support on this system! \n");
      WinMessageBox(HWND_DESKTOP, _drawCanvas,
	"No OpenGL support installed on this system. Use the OS/2 Selective Install utility to add OpenGL support.", "Error", 0,
	MB_ERROR | MB_OK);
      return;
    }

    if (!_hGLRC)
    {
      // Initialize OpenGL rendering
      // Set up the rendering pixel format
      _setUpPixelFormat();

      // Set up Palette
      _setUpPalette();

      // create a direct OpenGL context
      _hGLRC = pglCreateContext( _hab, _pVisualConfig, 0, TRUE );

      // free the visual config
      // EMX compiled apps bomb if you free the visual config!!
      // IBM says EMX free() may not be compatible with VAC++
      // calloc()/malloc() that OPENGL dll's are using
      // Anyway, shouldn't matter since memory amount is small
//      free( _pVisualConfig );
    }

    // initialize graphic
    graphicsInit();
  }

#ifdef USECREATEDC
//==================>>> vBaseGLCanvasPane::CreateDC <<<========================
  void vBaseGLCanvasPane::CreateDC(void)
  {
    // This overrides the CreateDC of vCanvasPane and creates
    // an OpenGL compatible DC, and then sets up the rendering stuff

//    vCanvasPane::CreateDC();   // we can have both regular DC
			       // and a OpenGL DC.
  }
#endif

//==================>>> vBaseGLCanvasPane::_setUpPixelFormat <<<==========================
  void vBaseGLCanvasPane::_setUpPixelFormat()
  {
    _doubleBuffer = 1;

    // prepare the mode
    if (_vGLmode & vGL_Indexed)   // Indexed mode *********************
    {
      // for now we don't support indexed mode, since OS/2 can
      // do a pretty good job of palette management itself on
      // 256 color machines anyway
      UserDebug(WindowEvents,"vBaseGLCanvasPane::_setUpPixelFormat: OpenGL starts (index mode not supported in OS/2)");

    }
    else    // RGBA mode ********************
    {
      UserDebug(WindowEvents,"vBaseGLCanvasPane::_setUpPixelFormat: OpenGL starts in RGB, Double buffering and Depth mode");

      int attribList[] = { PGL_RGBA, PGL_RED_SIZE, 2, PGL_GREEN_SIZE, 2,
	PGL_BLUE_SIZE, 2, PGL_ALPHA_SIZE, 1, PGL_DOUBLEBUFFER, PGL_None };

      // create a visual config
      _pVisualConfig = pglChooseConfig( _hab, attribList );

      // if nothing suitable, downgrade to single buffer and retry
      if ( _pVisualConfig == 0)
      {
	_doubleBuffer = 0;
	int attribList[] = { PGL_RGBA, PGL_RED_SIZE, 2, PGL_GREEN_SIZE, 2,
	  PGL_BLUE_SIZE, 2, PGL_ALPHA_SIZE, 1, PGL_SINGLEBUFFER, 0 };

	// create a visual config
	_pVisualConfig = pglChooseConfig( _hab, attribList );

	UserDebug(WindowEvents,"without Double buffering");
      }
      else
	UserDebug(WindowEvents,"with Double buffering");
    }

    if (_pVisualConfig == 0)
      {
	WinMessageBox(HWND_DESKTOP, _drawCanvas,
	  "pglChooseConfig failed.", "Error", 0,
	  MB_ERROR | MB_OK);
	exit(1);
      }

    UserDebug(WindowEvents,"\n");
  }

//==================>>> vBaseGLCanvasPane::_setUpPalette <<<==========================
  void vBaseGLCanvasPane::_setUpPalette()
  {
    // Index mode not supported in this release
/*
    PVOID pPal;

    int paletteSize;
    DescribePixelFormat(_hDC, _pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
    if (pfd.dwFlags & PFD_NEED_PALETTE)
    {
      paletteSize = 1 << pfd.cColorBits;
    }
    else
    {
      return;
    }
    pPal =  malloc(paletteSize * sizeof(RGB2));

    // build a simple RGB color palette
    {
      int i;
      for (i=0; i<paletteSize; ++i)
      {
	*ppal = SETRGB(255,255,255);
	ppal ++;
      }
    }

    _hPalette = GpiCreatePalette(_hab, 0L, LCOLF_CONSECRGB, paletteSize, pPal);
    free(pPal);

    if (_hPalette)
    {
      GpiSelectPalette(_hDC, _hPalette);
      ULONG cclr;
      WinRealizePalette ( WindowFromDC(_hDC), _hDC, &cclr)
    }
*/
  }

//==================>>> vBaseGLCanvasPane::graphicsInit <<<========================
  void vBaseGLCanvasPane::graphicsInit(void)
  {
    // Perform only the most basic operations, including getting the context
    pglMakeCurrent( _hab, _hGLRC, _drawCanvas );
  }

//================>>> vBaseGLCanvasPane::vglMakeCurrent <<<===============
  void vBaseGLCanvasPane::vglMakeCurrent(void)
  {
    pglMakeCurrent( _hab, _hGLRC, _drawCanvas );
  }

  //==================>>> vBaseGLCanvasPane::vglFlush <<<========================
  void vBaseGLCanvasPane::vglFlush(void)
  {
    if (_doubleBuffer)
	pglSwapBuffers(_hab, _drawCanvas);
    else
	glFlush();
  }

  //=====================>>> vBaseGLCanvasPane::Resize <<<============================
  void vBaseGLCanvasPane::Resize(int newW, int newH)
  {
    // This is the routine the user will override to intercept size changes
    vCanvasPane::Resize(newW,newH);
    pglMakeCurrent( _hab, _hGLRC, _drawCanvas );
    glViewport(0,0,newW,newH);
  }
