context: // Copyright Hugh Perkins 2004,2005,2006
  //
  // This program is free software; you can redistribute it and/or modify it
  // under the terms of the GNU General Public License as published by the
  // Free Software Foundation; either version 2 of the License, or
  // (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful, but
  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  // or FITNESS FOR A PARTICULAR PURVector3E. See the GNU General Public License for
  //  more details.
  //
  // You should have received a copy of the GNU General Public License along
  // with this program in the file licence.txt; if not, write to the
  // Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
  // 1307 USA
  // You can find the licence also on the web at:
  // http://www.opensource.org/licenses/gpl-license.php
  //
  
  //! \file
  //! \brief mgraphics contains certain wrapper routines around OpenGL/GLUT
  
  using System;
  using Tao.OpenGl;
  using Tao.FreeGlut;
  using MathGl;
  using System.Drawing;
  using Metaverse.Utility;
  
  namespace OSMP
  {
      class GraphicsHelperGl : IGraphicsHelper
      {
          int iWindowWidth = 1024;
          int iWindowHeight = 812;
  
          bool bCubeDefined = false;
          //bool bConeDefined = false;
          bool bCylinderDefined = false;
          bool bSphereDefined = false;
  
          //int LISTCONE = 1;
          int LISTCUBE = 2;
          int LISTSPHERE = 3;
          int LISTCYLINDER = 4;
  
          //! Feedback point buffer for OpenGL feedback, used by mvgraphics.cpp
          /*
          class FeedbackPointBufferItem
          {
              public double type;
              public double x;
              public double y;
              public override string ToString()
              {
                  return "<FeedbackPointBufferItem type=\"" + type.ToString() + "\" x=\"" + x.ToString() + "\" y=\"" + y.ToString() + " />";
              }
          }
          */
  
          Vector2 GetFeedbackPointBufferItem(float[] buffer, int index)
          {
              // each point takes 3 bytes:
              // type, x, y
              int vertexoffset = 3 * index + 1;
              return new Vector2(buffer[vertexoffset], buffer[vertexoffset + 1]);
          }
  
          Vector2 GetFeedbackLineBufferItem(float[] buffer, int lineindex, int vertexindex)
          {
              // each line takes 5 bytes:
              // type, x1, y1, x2, y2
              int vertexoffset = 5 * lineindex + 1 + vertexindex * 2;
              return new Vector2(buffer[vertexoffset], buffer[vertexoffset + 1]);
          }
  
          //! Feedback line buffer for OpenGL feedback, used by mvgraphics.cpp
          /*
          class FeedbackLineBufferItem
          {
              public double type;
              public Vector2[] vertices = new Vector2[2];
          }
          */
  
          public Vector3 GetMouseVector(Vector3 OurPos, Rot OurRot, int mousex, int mousey)
          {
              IRenderer renderer = RendererFactory.GetInstance();
  
              //Vector3 MouseVectorObserverAxes = new Vector3(-renderer.WindowWidth / 2 + mousex, -renderer.ScreenDistanceScreenCoords, renderer.WindowHeight / 2 - mousey);
              Vector3 MouseVectorObserverAxes = new Vector3(
                  renderer.ScreenDistanceScreenCoords,
                  renderer.WindowWidth / 2 - mousex,
                  renderer.WindowHeight / 2 - mousey);
              //LogFile.WriteLine("MouseVectorObserverAxes: " + MouseVectorObserverAxes);
              MouseVectorObserverAxes.Normalize();
              //LogFile.WriteLine("MouseVectorObserverAxes (normalized): " + MouseVectorObserverAxes);
              Vector3 MouseVectorWorldAxes = MouseVectorObserverAxes * OurRot.Inverse();
              //LogFile.WriteLine("MouseVectorWorldAxes: " + MouseVectorWorldAxes.ToString());
              MouseVectorWorldAxes.Normalize();
              return MouseVectorWorldAxes;
          }
  
          // we want to find out the length something of 1 world unit takes up in screen pixels when it is fDepth away from us
          // into the screen (along our x axis)
          // we draw a lines in the world, at depth fDepth (in world axes)
          // and we use an OpenGl FeedbackBuffer to find out how long that line is on the screen
          // ( see http://msdn.microsoft.com/library/en-us/opengl/glfunc02_3m42.asp )
          public double GetScalingFrom3DToScreen(double fDepth)
          {
              return RendererFactory.GetInstance().ScreenDistanceScreenCoords / fDepth / RendererFactory.GetInstance().NearClip;
  
              /*
              int iNumLines = 1;
              // each line uses five floats in the buffer:
              float[] feedbackbuffer = new float[iNumLines * 5];
  
              int[] viewport = new int[4];
              // This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window
              Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
  
              Gl.glLoadIdentity();
  
              RendererFactory.GetInstance().ApplyViewingMatrices();
  
              // rotate so z axis is up, and x axis is forward
              Gl.glRotatef(90f, 0.0f, 0.0f, 1.0f);
              Gl.glRotatef(90f, 0.0f, 1.0f, 0.0f);
  
              Gl.glFeedbackBuffer(iNumLines * 5, Gl.GL_2D, feedbackbuffer);
              Gl.glRenderMode(Gl.GL_FEEDBACK);
  
              Gl.glBegin(Gl.GL_LINES);
              Gl.glVertex3d(fDepth, -0.5, 0);
              Gl.glVertex3d(fDepth, 0.5, 0);
              Gl.glEnd();
  
              int iNumValues = Gl.glRenderMode(Gl.GL_RENDER);
  
              // A is distance of vector, at depth fDepth in world, in pixels
              // Test.WriteOut( feedbackbuffer );
              Vector2 VectorA = GetFeedbackLineBufferItem(feedbackbuffer, 0, 1) - GetFeedbackLineBufferItem(feedbackbuffer, 0, 0);
              double A = VectorA.Det();
  
              return A;
               */
          }
  
          // not to self: this is ugly, maybe simplify a little/lot?
          public Vector3 GetScreenPos(Vector3 ObserverPos, Rot ObserverRot, Vector3 TargetPos3D)
          {
              float[] feedbackbuffer = new float[1 * 3];
  
              Gl.glFeedbackBuffer(3, Gl.GL_2D, feedbackbuffer);
  
              int[] viewport = new int[4];
              // This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window
              Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
  
              Gl.glPushMatrix();
  
              Gl.glRenderMode(Gl.GL_FEEDBACK);
              Gl.glLoadIdentity();
  
              // rotate so z axis is up, and x axis is forward
              Gl.glRotatef(90f, 0.0f, 0.0f, 1.0f);
              Gl.glRotatef(90f, 0.0f, 1.0f, 0.0f);
  
              Rotate(ObserverRot.Inverse());
              Translate(-ObserverPos);
  
              Gl.glBegin(Gl.GL_POINTS);
              Gl.glVertex3f((float)TargetPos3D.x, (float)TargetPos3D.y, (float)TargetPos3D.z);
              Gl.glEnd();
  
              Gl.glRenderMode(Gl.GL_RENDER);
  
              Gl.glPopMatrix();
  
              //DEBUG(  "Screencoords of input vertex: " << FeedbackBuffer.Vertices[0].x << " " << FeedbackBuffer.Vertices[0].y ); // DEBUG
              Vector2 screenpoint = GetFeedbackPointBufferItem(feedbackbuffer, 0);
              Vector3 ScreenPos = new Vector3(
                  0,
                  RendererFactory.GetInstance().WindowWidth - screenpoint.x,
                  screenpoint.y
              );
  
              //DEBUG(  "screenpos: " << ScreenPos ); // DEBUG
  
              return ScreenPos;
          }
  
          public void SetColor(double r, double g, double b)
          {
              Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT_AND_DIFFUSE, new float[] { (float)r, (float)g, (float)b, 1.0f });
          }
  
          public void SetColor(Color color)
          {
              Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT_AND_DIFFUSE, new float[] { (float)color.r, (float)color.g, (float)color.b, 1.0f });
          }
  
          public void PrintText(string text)
          {
              foreach (char p in text)
              {
                  Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_TIMES_ROMAN_24, p);
              }
          }
  
          public void ScreenPrintText(int x, int y, string text)
          {
              Gl.glMatrixMode(Gl.GL_PROJECTION);
              Gl.glPushMatrix();
              Gl.glLoadIdentity();
              Gl.glOrtho(0, iWindowWidth, 0, iWindowHeight, -1.0f, 1.0f);
              Gl.glMatrixMode(Gl.GL_MODELVIEW);
              Gl.glPushMatrix();
              Gl.glLoadIdentity();
              Gl.glPushAttrib(Gl.GL_DEPTH_TEST);
              Gl.glDisable(Gl.GL_DEPTH_TEST);
              Gl.glRasterPos2i(x, y);
              PrintText(text);
              Gl.glPopAttrib();
              Gl.glMatrixMode(Gl.GL_PROJECTION);
              Gl.glPopMatrix();
              Gl.glMatrixMode(Gl.GL_MODELVIEW);
              Gl.glPopMatrix();
          }
  
          public void Rotate(Rot rot)
          {
              double fRotAngle = 0;
              Vector3 vAxis = new Vector3();
              mvMath.Rot2AxisAngle(ref vAxis, ref fRotAngle, rot);
              Gl.glRotatef((float)(fRotAngle / Math.PI * 180), (float)vAxis.x, (float)vAxis.y, (float)vAxis.z);
          }
  
          public void DrawSquareXYPlane()
          {
              // Test.Debug(  "DrawSquareXYPlanes" ); // Test.Debug
              Gl.glBegin(Gl.GL_LINE_LOOP);
              Gl.glVertex3f(-0.5f, -0.5f, 0f);
              Gl.glVertex3f(-0.5f, 0.5f, 0f);
              Gl.glVertex3f(0.5f, 0.5f, 0f);
              Gl.glVertex3f(0.5f, -0.5f, 0f);
              Gl.glEnd();
          }
  
          public void DrawParallelSquares(int iNumSlices)
          {
              // Test.Debug(  "DrawParallelSquares" ); // Test.Debug
              Gl.glPushMatrix();
              Gl.glTranslated(0, 0, -0.5);
              double fSpacing = 1.0 / (double)iNumSlices;
              for (int i = 0; i <= iNumSlices; i++)
              {
                  DrawSquareXYPlane();
                  Gl.glTranslated(0, 0, fSpacing);
              }
              Gl.glPopMatrix();
          }
  
          public void DrawWireframeBox(int iNumSlices)
          {
              // Test.Debug(  "DrawWireframeBox" ); // Test.Debug
              Gl.glPushMatrix();
              DrawParallelSquares(iNumSlices);
              Gl.glPushMatrix();
              Gl.glRotatef(90f, 1f, 0f, 0f);
              DrawParallelSquares(iNumSlices);
  
              Gl.glPopMatrix();
  
              Gl.glRotatef(90f, 0f, 1f, 0f);
              DrawParallelSquares(iNumSlices);
  
              Gl.glPopMatrix();
          }
  
          public void DrawCone()
          {
              //if (!bConeDefined)
              //{
                //  Gl.glNewList(LISTCONE, Gl.GL_COMPILE);
  
                  Gl.glPushMatrix();
                  Glu.GLUquadric quadratic = Glu.gluNewQuadric();   // Create A Pointer To The Quadric Object
                  Glu.gluQuadricNormals(quadratic, Glu.GLU_SMOOTH); // Create Smooth Normals
                  Glu.gluQuadricTexture(quadratic, 32);  // Create Texture Coords
  
gt:                 Gl.glTranslated(0.0f, 0.0f, -0.5f);   // Center The Cone