Robotic Control & 3-D GUIs
by Hank Jones and Martin Synder

Listing One
#include "glutm/window.h"
// C3DGUIWindow is derived from GlutWindow, which performs all system 
// initialization for us. InitializeWindowValues performs additional 
// initialization for our app to specify drawing parameters we require.
void C3DGUIWindow::InitializeWindowValues()
{
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE); // An optimization that prevents OpenGL from 
                          // rendering sides of an object that cannot be seen.
  glCullFace(GL_BACK);    // So, don't worry about rendering the 'back' side 
                          // of objects since they should all be solids
  glClearDepth(1.0);
  glDepthRange(0.0, 1.0);
  glClearColor(0.3, 0.3, 0.5, 0.0);  // Provides a sky blue background
  SetLightingValues();
}


Listing Two
class CStatePkt
{
    char*  m_sName; // e.g. "Huey"
    char*  m_sType; // e.g. "FFSR"
    char*  m_sSource;   // e.g. "Louie"
    double x;       // e.g. 2.348756;  x = 0.0 at table center
    double y;       // e.g. 1.235445;  y = 0.0 at table center
    double z;       // usually 0.0 (Robots and objects move on table surface)
    double yaw;     // ranges from 0 to 2p
    double roll;    // usually 0.0 for our robots and objects
    double pitch;   // usually 0.0 for our robots and objects
};

Listing Three
// nWrapParam can be GL_REPEAT or GL_CLAMP
// GL_REPEAT will tile the texture; GL_CLAMP will stretch it out
// nEnvParam can be GL_MODULATE or GL_DECAL (others values are possible 
//    but we don't use them)
// GL_MODULATE is makes the texture somewhat see-through; GL_DECAL is 
//    not see-through at all
// nWrapParam and nEnvParam are basically the only options 
//    needed to specify in initialization
bool CGUIShape::InitializeTexture(GLenum nWrapParam, Glenum nEnvParam)
{
  if (m_pTextureData == NULL) return false;  
     // m_pTextureData is defined in the constructor, and points to
     //   the proper texture bitmap structure if it exists
  m_pTexture = new GltTexture();
  m_pTexture->init(m_pTextureData);
  m_pTexture->set();
  m_nTextureEnvParam = nEnvParam;
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, nWrapParam);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, nWrapParam);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  return true;
}
// CGUIFreeFlyer is a child class of CGUIEntity, which inherits from CGUIShape
int CGUIFreeFlyer::CreateDisplayList()
{
  int nIndex;
  double xScale, yScale, zScale;
  InitializeTexture(GL_REPEAT, GL_DECAL);
  GLfloat sReflectPlane[] = {1.0, 1.0, 0.0, 0.0};
  GLfloat tReflectPlane[] = {0.0, 0.0, 1.0, 0.0};
  GLUquadric *qobj;
  // The FFSR is represented graphically by a cube. It has to be scaled to 
  // achieve the proper dimensions
  xScale = FFSR_DIAMETER;
  yScale = FFSR_DIAMETER;
  zScale = FFSR_HEIGHT;
  nIndex = glGenLists(1);
  glNewList(nIndex, GL_COMPILE);    
  glColor3f(1.0, 1.0, 1.0);
  glPushMatrix();
  // Start Texture-related calls
  if (m_pTexture->id() != 0) {
    m_pTexture->set();
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, m_nTextureEnvParam);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGenfv(GL_T, GL_OBJECT_PLANE, tReflectPlane);
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
    glTexGenfv(GL_S, GL_OBJECT_PLANE, sReflectPlane);
    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    glEnable(GL_TEXTURE_2D);
  }
  // End Texture-related calls
    glTranslatef(0, 0, FFSR_HEIGHT * 0.5);
    glScalef(xScale, yScale, zScale);
    glutSolidCube(1.0);
  // Texture-disabling calls
  if (m_pTexture->id() != 0) {
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
  }
  glPopMatrix();
  glEndList();
  return nIndex;
}

Listing Four
int CGUIEntity::ConsiderIncomingStatePkt(CStatePkt *pPkt)
{
  int nDigested = 0;
  if (ShouldDigestThisStatePkt(pPkt)) {
    nDigested = ProcessStatePkt(pPkt);  
    // printf("Home for packet from %s was found!\n", pPkt->sSource);
  }
  // Send it to the child objects to see if one of them will digest it
  // Won't send it to the child nodes if it returned an answer above
  CGUIEntity* pChild;
  for (int j=0; !nDigested && j<size(); j++) {
    if (pChild = (CGUIEntity*)(*this)[j].get()) {
        nDigested = (pChild->ConsiderIncomingStatePkt(pPkt));
    }
  }
  return nDigested;
}
// Handles packets for objects that it senses (i.e. served as the source)
bool CGUIEntity::ShouldDigestThisStatePkt(CStatePkt *pPkt)
{
  return (strcmp(pPkt->sSource, GetName()) == 0);
}
CGUIEntity* CGUIEntity::FindObjectPtrByName(char *sName)
{
  if (strcmp(Name(), sName) == 0) return this;
  // Send it to the child objects to see if one of them is the right name
  //  Check the child nodes, and return their answer if they give one
  CGUIEntity* pChild;
  CGUIEntity* result = NULL;
  for (int j=0; j<size(); j++) {
    if (pChild = (CGUIEntity*)(*this)[j].get()) {
      result = pChild->FindObjectPtrByName(sName);
      if (result != NULL) return result;
    }
  }
  return NULL;
}
// The following two functions are virtual for CGUIEntity. They're implemented
// by CGUIRobot for all robots, including FFSRs (which inherit from CGUIRobot)
bool CGUIRobot::ProcessStatePkt(CStatePkt *pPkt)
{
  CGUIEntity* pObject = NULL;
  if (!(pObject = FindObjectPtrByName(pPkt->sObjName))) {
    return false;
  }
  if (!pObject->SetStateData(pPkt)) {
    return false;
  } 
  pObject->SetLastUpdateTime();
  // printf("Processed Object %s from %s\n", pPkt->sObjName, pPkt->sSource);
  return true;
}


Listing Five
void OnDisplay()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  m_pEntityRoot->Draw();
}
void CGUIShape::Draw() const
{
  if (!ShouldDraw()) return;
  // Save time by not calling this if there are no children; 
  // Default is that children exist
  if (m_bHasChildrenToDraw) GltShapes::draw();    
    // Calling GltShapes::draw(), not GltShape::draw() to get 
 // the child objects drawn
  if (GetDisplayListID()) {     // A display list exists
    int nMode = 0;
    glGetIntegerv(GL_RENDER_MODE, &nMode);
    if (nMode == GL_SELECT) glLoadName(GetDisplayListID());
    glPushMatrix();
      color().glColor();
      glTranslatef(translation()[0], translation()[1], translation()[2]);
      glScalef(scale()[0], scale()[1], scale()[2]); 
      // Perform a 3-2-1 coordinate transformation
      glRotatef(rotation()[0]*RAD2DEG, 0, 0, 1);
      glRotatef(rotation()[1]*RAD2DEG, 0, 1, 0);
      glRotatef(rotation()[2]*RAD2DEG, 1, 0, 0);
      if (m_nDisplayListID != 0) glCallList(GetDisplayListID());
    glPopMatrix();
  }
}


Listing Six
// Basic starting POV looks at the origin of the coordinate system from the 
// (1,1,1) position  with the z axis pointing up in the viewport
CWindowPOV::CWindowPOV
{
  SetPOV(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
}
void CWindowPOV::SetPOV(double EX, double EY, double EZ, double CX, 
                    double CY, double CZ, double UX, double UY, double UZ)
{
  SetEyeLocation(EX, EY, EZ);
  SetFocusPoint(CX, CY, CZ);
  SetUpVector(UX, UY, UZ);
}
void C3DGUIWindow::UpdateWindowViewport(CWindowPOV *POVinfo)
{
  glMatrixMode(GL_MODELVIEW); // Ensure you're manipulating model view matrix,
  glLoadIdentity();           // then reset it before calling gluLookAt()
  gluLookAt(POVinfo->Eye(0), POVinfo->Eye(1), POVinfo->Eye(2), 
    POVinfo->Focus(0), POVinfo->Focus(1), POVinfo->Focus(2),
    POVinfo->Up(0), POVinfo->Up(1), POVinfo->Up(2));
}






4


