/*
 * "$Id: motif.c,v 1.4 2003/06/22 23:44:47 mike Exp $"
 *
 * OpenGL example using Motif.
 *
 * Copyright 2003 by Michael Sweet, All Rights Reserved.
 */

/*
 * Include necessary headers...
 */

#include <stdio.h>
#include <stdlib.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <GL/GLwMDrawA.h>


/*
 * Globals...
 */

float		CubeRotation[3],	/* Rotation of cube */
		CubeRate[3];		/* Rotation rate of cube */
int		CubeMouseButton,	/* Button that was pressed */
		CubeMouseX,		/* Start X position of mouse */
		CubeMouseY;		/* Start Y position of mouse */
int		CubeWidth,		/* Width of window */
		CubeHeight;		/* Height of window */
GLuint		CubeFont;		/* Display list base for font */
Widget		CubeShell;		/* Application shell */
XtAppContext	CubeContext;		/* Application context */
Widget		CubeGLArea;		/* OpenGL drawing area */
GLXContext	CubeGLContext;		/* OpenGL drawing context */


/*
 * Functions...
 */

void	DisplayCB(void);
void	InitCB(Widget w, void *ud, GLwDrawingAreaCallbackStruct *cd);
void	InputCB(Widget w, void *ud, GLwDrawingAreaCallbackStruct *cd);
void	ReshapeCB(Widget w, void *ud, GLwDrawingAreaCallbackStruct *cd);
void	TimeOutCB(void);


/*
 * 'main()' - Main entry for example program.
 */

int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line args */
{
  Widget	form;			/* Form management widget */
  XtAppContext	context;		/* Application context */
  static char	*fallback[] =		/* Fallback resources */
			{
			  "Motif.geometry: 774x588",
			  NULL
			};


 /*
  * Initialize the application window and manager widgets...
  */

  CubeShell = XtVaAppInitialize(
        	  &CubeContext, "Motif", NULL, 0, &argc, argv,
		  fallback,
        	  XmNtitle,    "Motif Example",
		  XmNiconName, "Motif",
		  NULL);
  form  = XtVaCreateManagedWidget(
              "form", xmFormWidgetClass, CubeShell,
	      NULL);

 /*
  * Create the OpenGL drawing area...
  */

  CubeGLArea = XtVaCreateManagedWidget(
                   "drawingArea", glwMDrawingAreaWidgetClass, form,
                   GLwNrgba,		True,
                   GLwNdoublebuffer,	True,
                   GLwNdepthSize,	16,
                   XmNtopAttachment,	XmATTACH_FORM,
                   XmNbottomAttachment,	XmATTACH_FORM,
                   XmNleftAttachment,	XmATTACH_FORM,
                   XmNrightAttachment,	XmATTACH_FORM,
                   NULL);

 /*
  * Set callbacks and timeout processing...
  */

  XtAddCallback(CubeGLArea, GLwNexposeCallback,
                (XtCallbackProc)DisplayCB, NULL);
  XtAddCallback(CubeGLArea, GLwNginitCallback,
                (XtCallbackProc)InitCB, NULL);
  XtAddCallback(CubeGLArea, GLwNresizeCallback,
                (XtCallbackProc)ReshapeCB, NULL);
  XtAddCallback(CubeGLArea, GLwNinputCallback,
                (XtCallbackProc)InputCB, NULL);

 /*
  * Setup remaining globals...
  */

  CubeWidth       = 774;
  CubeHeight      = 588;
  CubeRotation[0] = 45.0f;
  CubeRotation[1] = 45.0f;
  CubeRotation[2] = 45.0f;
  CubeRate[0]     = 1.0f;
  CubeRate[1]     = 1.0f;
  CubeRate[2]     = 1.0f;

 /*
  * Loop forever...
  */

  XtRealizeWidget(CubeShell);
  XtAppMainLoop(CubeContext);

  return (0);
}


/*
 * 'DisplayCB()' - Display callback.
 */

void
DisplayCB(void)
{
  int			i, j;		/* Looping vars */
  XVisualInfo		*info;		/* Drawing area visual */
  XFontStruct		*font;		/* X font information */
  static const GLfloat	corners[8][3] =	/* Corner vertices */
			{
			  {  1.0f,  1.0f,  1.0f },	/* Front top right */
			  {  1.0f, -1.0f,  1.0f },	/* Front bottom right */
			  { -1.0f, -1.0f,  1.0f },	/* Front bottom left */
			  { -1.0f,  1.0f,  1.0f },	/* Front top left */
			  {  1.0f,  1.0f, -1.0f },	/* Back top right */
			  {  1.0f, -1.0f, -1.0f },	/* Back bottom right */
			  { -1.0f, -1.0f, -1.0f },	/* Back bottom left */
			  { -1.0f,  1.0f, -1.0f }	/* Back top left */
			};
  static const int	sides[6][4] =	/* Sides */
			{
			  { 0, 1, 2, 3 },		/* Front */
			  { 4, 5, 6, 7 },		/* Back */
			  { 0, 1, 5, 4 },		/* Right */
			  { 2, 3, 7, 6 },		/* Left */
			  { 0, 3, 7, 4 },		/* Top */
			  { 1, 2, 6, 5 }		/* Bottom */
			};
  static const GLfloat	colors[6][3] =	/* Colors */
			{
			  { 1.0f, 0.0f, 0.0f },		/* Red */
			  { 0.0f, 1.0f, 0.0f },		/* Green */
			  { 1.0f, 1.0f, 0.0f },		/* Yellow */
			  { 0.0f, 0.0f, 1.0f },		/* Blue */
			  { 1.0f, 0.0f, 1.0f },		/* Magenta */
			  { 0.0f, 1.0f, 1.0f }		/* Cyan */
			};


 /*
  * Clear the window...
  */

  glViewport(0, 0, CubeWidth, CubeHeight);
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Setup the matrices...
  */

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-2.0f, 2.0f,
          -2.0f * CubeHeight / CubeWidth, 2.0f * CubeHeight / CubeWidth,
          -2.0f, 2.0f);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glRotatef(CubeRotation[0], 1.0f, 0.0f, 0.0f);
  glRotatef(CubeRotation[1], 0.0f, 1.0f, 0.0f);
  glRotatef(CubeRotation[2], 0.0f, 0.0f, 1.0f);

 /*
  * Draw the cube...
  */

  glEnable(GL_DEPTH_TEST);

  glBegin(GL_QUADS);

  for (i = 0; i < 6; i ++)
  {
    glColor3fv(colors[i]);
    for (j = 0; j < 4; j ++)
      glVertex3fv(corners[sides[i][j]]);
  }

  glEnd();

 /*
  * Draw lines coming out of the cube...
  */

  glColor3f(1.0f, 1.0f, 1.0f);

  glBegin(GL_LINES);
    glVertex3f(0.0f, 0.0f, -1.5f);
    glVertex3f(0.0f, 0.0f, 1.5f);

    glVertex3f(-1.5f, 0.0f, 0.0f);
    glVertex3f(1.5f, 0.0f, 0.0f);

    glVertex3f(0.0f, 1.5f, 0.0f);
    glVertex3f(0.0f, -1.5f, 0.0f);
  glEnd();

 /*
  * Draw text for each side...
  */

  glPushAttrib(GL_LIST_BIT);
    glListBase(CubeFont - ' ');

    glRasterPos3f(0.0f, 0.0f, -1.5f);
    glCallLists(4, GL_BYTE, "Back");

    glRasterPos3f(0.0f, 0.0f, 1.5f);
    glCallLists(5, GL_BYTE, "Front");

    glRasterPos3f(-1.5f, 0.0f, 0.0f);
    glCallLists(4, GL_BYTE, "Left");

    glRasterPos3f(1.5f, 0.0f, 0.0f);
    glCallLists(5, GL_BYTE, "Right");

    glRasterPos3f(0.0f, 1.5f, 0.0f);
    glCallLists(3, GL_BYTE, "Top");

    glRasterPos3f(0.0f, -1.5f, 0.0f);
    glCallLists(6, GL_BYTE, "Bottom");
  glPopAttrib();

 /*
  * Swap the back buffer with the front buffer...
  */

  GLwDrawingAreaSwapBuffers(CubeGLArea);
}


/*
 * 'InitCB()' - Initialization callback.
 */

void
InitCB(Widget                       w,	/* I - Widget */
       void                         *ud,/* I - User data */
       GLwDrawingAreaCallbackStruct *cd)/* I - Callback data */
{
  XVisualInfo		*info;		/* Drawing area visual */
  XFontStruct		*font;		/* X font information */


 /*
  * Initialize the OpenGL context for drawing...
  */

  XtVaGetValues(CubeGLArea, GLwNvisualInfo, &info, NULL);
  CubeGLContext = glXCreateContext(XtDisplay(CubeShell), info,
	                           NULL, GL_TRUE);

  if (!CubeGLContext)
  {
    puts("Unable to create OpenGL context!");
    exit(1);
  }

  GLwDrawingAreaMakeCurrent(CubeGLArea, CubeGLContext);

 /*
  * Setup font...
  */

  font     = XLoadQueryFont(XtDisplay(CubeShell),
                            "-*-courier-bold-r-normal--14-*-*-*-*-*-*-*");
  CubeFont = glGenLists(96);

  glXUseXFont(font->fid, ' ', 96, CubeFont);

 /*
  * Activate the timeout procedure to rotate the cube...
  */

  XtAppAddTimeOut(CubeContext, 20,
	          (XtTimerCallbackProc)TimeOutCB, NULL);
}


/*
 * 'InputCB()' - Input callback.
 */

void
InputCB(Widget                       w,	/* I - Widget */
        void                         *ud,
					/* I - User data */
        GLwDrawingAreaCallbackStruct *cd)
					/* I - Callback data */
{
  int	x,				/* X position */
	y;				/* Y position */


  switch (cd->event->type)
  {
    case ButtonPress :
       /*
        * Save the initial mouse button + position...
	*/

        CubeMouseButton = cd->event->xbutton.button;
        CubeMouseX      = cd->event->xbutton.x;
        CubeMouseY      = cd->event->xbutton.y;

       /*
	* Zero-out the rotation rates...
	*/

	CubeRate[0] = 0.0f;
	CubeRate[1] = 0.0f;
	CubeRate[2] = 0.0f;
        break;

    case MotionNotify :
       /*
	* Get the mouse movement...
	*/

	x = cd->event->xmotion.x - CubeMouseX;
	y = cd->event->xmotion.y - CubeMouseY;

       /*
	* Update the cube rotation rate based upon the mouse
	* movement and button...
	*/

	switch (CubeMouseButton)
	{
	  case 0 :			/* Button 1 */
	      CubeRate[0] = 0.01f * y;
              CubeRate[1] = 0.01f * x;
	      CubeRate[2] = 0.0f;
	      break;

	  case 1 :			/* Button 2 */
	      CubeRate[0] = 0.0f;
	      CubeRate[1] = 0.01f * y;
              CubeRate[2] = 0.01f * x;
	      break;

	  default :			/* Button 3 */
	      CubeRate[0] = 0.01f * y;
	      CubeRate[1] = 0.0f;
              CubeRate[2] = 0.01f * x;
	      break;
	}
        break;
  }
}


/*
 * 'ReshapeCB()' - Resize callback.
 */

void
ReshapeCB(Widget                       w,
					/* I - Widget */
          void                         *ud,
					/* I - User data */
          GLwDrawingAreaCallbackStruct *cd)
					/* I - Callback data */
{
 /*
  * Save the current width and height...
  */

  CubeWidth  = cd->width;
  CubeHeight = cd->height;
}


/*
 * 'TimeOutCB()' - Rotate and redraw the cube.
 */

void
TimeOutCB(void)
{
  CubeRotation[0] += CubeRate[0];
  CubeRotation[1] += CubeRate[1];
  CubeRotation[2] += CubeRate[2];

  if (CubeRate[0] || CubeRate[1] || CubeRate[2])
    XmRedisplayWidget(CubeGLArea);

  XtAppAddTimeOut(CubeContext, 20,
                  (XtTimerCallbackProc)TimeOutCB, NULL);
}


/*
 * End of "$Id: motif.c,v 1.4 2003/06/22 23:44:47 mike Exp $".
 */
