code to draw engine block
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 1 Aug 2006 20:03:05 +0000 (20:03 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 1 Aug 2006 20:03:05 +0000 (20:03 +0000)
progs/demos/engine.c

index 8ef7346..143b02a 100644 (file)
@@ -47,6 +47,7 @@ typedef struct
    GLuint CrankList;
    GLuint ConnRodList;
    GLuint PistonList;
+   GLuint BlockList;
 } Engine;
 
 
@@ -80,6 +81,7 @@ typedef struct
    GLboolean UseLists;
    GLboolean DrawBox;
    GLboolean ShowInfo;
+   GLboolean ShowBlock;
 } RenderInfo;
 
 
@@ -87,9 +89,10 @@ static GLUquadric *Q;
 
 static GLfloat Theta = 0.0;
 
-static GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
-static GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
-static GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
+static const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
+static const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
+static const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
+static const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 };
 
 static GLuint TextureObj;
 static GLint WinWidth = 800, WinHeight = 500;
@@ -113,7 +116,7 @@ static Engine Engines[NUM_ENGINES] =
       0.25, /* CrankPinRadius */
       0.3,  /* CrankJournalRadius */
       0.4,  /* CrankJournalLength */
-      1.3,  /* ConnectingRodLength */
+      1.5,  /* ConnectingRodLength */
       0.1   /* ConnectingRodThickness */
    },
    {
@@ -129,7 +132,7 @@ static Engine Engines[NUM_ENGINES] =
       0.25, /* CrankPinRadius */
       0.3,  /* CrankJournalRadius */
       0.4,  /* CrankJournalLength */
-      1.3,  /* ConnectingRodLength */
+      1.5,  /* ConnectingRodLength */
       0.1   /* ConnectingRodThickness */
    },
    {
@@ -145,7 +148,7 @@ static Engine Engines[NUM_ENGINES] =
       0.25, /* CrankPinRadius */
       0.3,  /* CrankJournalRadius */
       0.4,  /* CrankJournalLength */
-      1.3,  /* ConnectingRodLength */
+      1.5,  /* ConnectingRodLength */
       0.1   /* ConnectingRodThickness */
    }
 };
@@ -180,6 +183,7 @@ InitRenderInfo(RenderInfo *render)
    render->Texture = GL_FALSE;
    render->DrawBox = GL_FALSE;
    render->ShowInfo = GL_TRUE;
+   render->ShowBlock = GL_FALSE;
    render->UseLists = GL_FALSE;
 }
 
@@ -190,6 +194,9 @@ InitRenderInfo(RenderInfo *render)
 static void
 SetRenderState(RenderMode mode)
 {
+   static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 };
+   static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 };
+
    /* defaults */
    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
@@ -198,6 +205,7 @@ SetRenderState(RenderMode mode)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
+   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2);
 
    switch (mode) {
    case LIT:
@@ -214,6 +222,7 @@ SetRenderState(RenderMode mode)
       glEnable(GL_TEXTURE_2D);
       glEnable(GL_TEXTURE_GEN_S);
       glEnable(GL_TEXTURE_GEN_T);
+      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4);
       break;
    default:
       ;
@@ -270,6 +279,19 @@ PistonShaftPosition(const Engine *eng, int piston)
 
 
 /**
+ * Compute distance between two adjacent pistons
+ */
+static float
+PistonSpacing(const Engine *eng)
+{
+   const int pistonsPerCrank = eng->Pistons / eng->Cranks;
+   const float z0 = PistonShaftPosition(eng, 0);
+   const float z1 = PistonShaftPosition(eng, pistonsPerCrank);
+   return z1 - z0;
+}
+
+
+/**
  * (x0, y0) = position of big end on crankshaft
  * (x1, y1) = position of small end on piston
  */
@@ -518,6 +540,144 @@ DrawPositionedConnectingRod(const Engine *eng, float crankAngle)
 
 
 /**
+ * Draw a square with a hole in middle.
+ */
+static void
+SquareWithHole(float squareSize, float holeRadius)
+{
+   int i;
+   glBegin(GL_QUAD_STRIP);
+   glNormal3f(0, 0, 1);
+   for (i = 0; i <= 360; i += 5) {
+      const float x1 = holeRadius * cos(DEG_TO_RAD(i));
+      const float y1 = holeRadius * sin(DEG_TO_RAD(i));
+      float x2, y2;
+      if (i > 315 || i <= 45) {
+         x2 = squareSize;
+         y2 = squareSize * tan(DEG_TO_RAD(i));
+      }
+      else if (i > 45 && i <= 135) {
+         x2 = -squareSize * tan(DEG_TO_RAD(i - 90));
+         y2 = squareSize;
+      }
+      else if (i > 135 && i <= 225) {
+         x2 = -squareSize;
+         y2 = -squareSize * tan(DEG_TO_RAD(i-180));
+      }
+      else if (i > 225 && i <= 315) {
+         x2 = squareSize * tan(DEG_TO_RAD(i - 270));
+         y2 = -squareSize;
+      }
+      glVertex2f(x1, y1); /* inner circle */
+      glVertex2f(x2, y2); /* outer square */
+   }
+   glEnd();
+}
+
+
+/**
+ * Draw block with hole through middle.
+ * Hole is centered on Z axis.
+ * Bottom of block is at z=0, top of block is at z = blockHeight.
+ * index is in [0, count - 1] to determine which block faces are drawn.
+ */
+static void
+DrawBlockWithHole(float blockSize, float blockHeight, float holeRadius,
+                  int index, int count)
+{
+   const int slices = 30, stacks = 4;
+   const float x = blockSize;
+   const float y = blockSize;
+   const float z0 = 0;
+   const float z1 = blockHeight;
+
+   assert(index < count);
+   assert(Q);
+   gluQuadricOrientation(Q, GLU_INSIDE);
+
+   glBegin(GL_QUADS);
+   /* +X face */
+   glNormal3f(1, 0, 0);
+   glVertex3f( x, -y, z0);
+   glVertex3f( x, y, z0);
+   glVertex3f( x, y, z1);
+   glVertex3f( x, -y, z1);
+   /* -X face */
+   glNormal3f(-1, 0, 0);
+   glVertex3f(-x, -y, z1);
+   glVertex3f(-x, y, z1);
+   glVertex3f(-x, y, z0);
+   glVertex3f(-x, -y, z0);
+   if (index == 0) {
+      /* +Y face */
+      glNormal3f(0, 1, 0);
+      glVertex3f(-x, y, z1);
+      glVertex3f( x, y, z1);
+      glVertex3f( x, y, z0);
+      glVertex3f(-x, y, z0);
+   }
+   if (index == count - 1) {
+      /* -Y face */
+      glNormal3f(0, -1, 0);
+      glVertex3f(-x, -y, z0);
+      glVertex3f( x, -y, z0);
+      glVertex3f( x, -y, z1);
+      glVertex3f(-x, -y, z1);
+   }
+   glEnd();
+
+   /* cylinder / hole */
+   gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks);
+
+   /* face at z0 */
+   glPushMatrix();
+   glRotatef(180, 1, 0, 0);
+   SquareWithHole(blockSize, holeRadius);
+   glPopMatrix();
+
+   /* face at z1 */
+   glTranslatef(0, 0, z1);
+   SquareWithHole(blockSize, holeRadius);
+
+   gluQuadricOrientation(Q, GLU_OUTSIDE);
+}
+
+
+/**
+ * Draw the engine block.
+ */
+static void
+DrawEngineBlock(const Engine *eng)
+{
+   const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight;
+   const float cylRadius = 1.01 * eng->PistonRadius;
+   const float blockSize = 0.5 * PistonSpacing(eng);
+   const int pistonsPerCrank = eng->Pistons / eng->Cranks;
+   int i;
+
+   for (i = 0; i < eng->Pistons; i++) {
+      const float z = PistonShaftPosition(eng, i);
+      const int crank = i / pistonsPerCrank;
+      int k;
+
+      glPushMatrix();
+         glTranslatef(0, 0, z);
+
+         /* additional rotation for kth piston per crank */
+         k = i % pistonsPerCrank;
+         glRotatef(k * -eng->V_Angle, 0, 0, 1);
+
+         /* the block */
+         glRotatef(-90, 1, 0, 0);
+         glTranslatef(0, 0, eng->Throw * 2);
+         DrawBlockWithHole(blockSize, blockHeight, cylRadius,
+                           crank, eng->Cranks);
+      glPopMatrix();
+   }
+}
+
+
+/**
  * Generate display lists for engine parts.
  */
 static void
@@ -538,6 +698,11 @@ GenerateDisplayLists(Engine *eng)
    glNewList(eng->PistonList, GL_COMPILE);
    DrawPiston(eng);
    glEndList();
+
+   eng->BlockList = glGenLists(1);
+   glNewList(eng->BlockList, GL_COMPILE);
+   DrawEngineBlock(eng);
+   glEndList();
 }
 
 
@@ -553,10 +718,11 @@ FreeDisplayLists(Engine *eng)
    eng->ConnRodList = 0;
    glDeleteLists(eng->PistonList, 1);
    eng->PistonList = 0;
+   glDeleteLists(eng->BlockList, 1);
+   eng->BlockList = 0;
 }
 
 
-
 /**
  * Draw complete engine.
  * \param eng  description of engine to draw
@@ -602,10 +768,32 @@ DrawEngine(const Engine *eng, float crankAngle)
          glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ConnRodColor);
          glColor4fv(ConnRodColor);
          DrawPositionedConnectingRod(eng, rot);
-
       glPopMatrix();
    }
 
+   if (Render.ShowBlock) {
+      const GLboolean blend = glIsEnabled(GL_BLEND);
+
+      glDepthMask(GL_FALSE);
+      if (!blend) {
+         glEnable(GL_BLEND);
+      }
+      glEnable(GL_CULL_FACE);
+
+      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, BlockColor);
+      glColor4fv(BlockColor);
+      if (eng->CrankList)
+         glCallList(eng->BlockList);
+      else
+         DrawEngineBlock(eng);
+
+      glDisable(GL_CULL_FACE);
+      glDepthMask(GL_TRUE);
+      if (!blend) {
+         glDisable(GL_BLEND);
+      }
+   }
+
    glPopMatrix();
 }
 
@@ -745,9 +933,9 @@ Draw(void)
 
       glPushMatrix();
          glTranslatef(0, -0.75, 0);
-         DrawEngine(Engines + CurEngine, Theta);
          if (Render.DrawBox)
             DrawBox();
+         DrawEngine(Engines + CurEngine, Theta);
       glPopMatrix();
 
    glPopMatrix();
@@ -900,6 +1088,12 @@ OptDisplayLists(void)
 }
 
 static void
+OptShowBlock(void)
+{
+   Render.ShowBlock = !Render.ShowBlock;
+}
+
+static void
 OptShowInfo(void)
 {
    Render.ShowInfo = !Render.ShowInfo;
@@ -940,8 +1134,9 @@ static const MenuInfo MenuItems[] = {
    { "Change Engine", 'e', OptChangeEngine },
    { "Rendering Style", 'm', OptRenderMode },
    { "Display Lists", 'd', OptDisplayLists },
+   { "Show Block", 'b', OptShowBlock },
    { "Show Info", 'i', OptShowInfo },
-   { "Show Box", 'b', OptShowBox },
+   { "Show Box", 'x', OptShowBox },
    { "Exit", 27, OptExit },
    { NULL, 'r', OptRotate },
    { NULL, 0, NULL }
@@ -1070,7 +1265,6 @@ Init(void)
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
    glEnable(GL_NORMALIZE);
 
-   glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
    InitViewInfo(&View);