Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Demo of off-screen Mesa rendering
  3.  *
  4.  * See Mesa/include/GL/osmesa.h for documentation of the OSMesa functions.
  5.  *
  6.  * If you want to render BIG images you'll probably have to increase
  7.  * MAX_WIDTH and MAX_Height in src/config.h.
  8.  *
  9.  * This program is in the public domain.
  10.  *
  11.  * Brian Paul
  12.  *
  13.  * PPM output provided by Joerg Schmalzl.
  14.  * ASCII PPM output added by Brian Paul.
  15.  *
  16.  * Usage: osdemo [filename]
  17.  */
  18.  
  19.  
  20. #include <math.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <assert.h>
  25. #define GL_GLEXT_PROTOTYPES
  26. #include "GL/osmesa.h"
  27. #include <GL/glext.h>
  28. #include "GL/glu.h"
  29. #include "shaderutil.h"
  30.  
  31.  
  32. static int Width = 500;
  33. static int Height = 400;
  34.  
  35. int check_events();
  36.  
  37. GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
  38. GLfloat angle = 0.0;
  39.  
  40. GLboolean animate = GL_TRUE;    /* Animation */
  41. GLfloat eyesep = 5.0;           /* Eye separation. */
  42. GLfloat fix_point = 40.0;       /* Fixation point distance.  */
  43. GLfloat left, right, asp;       /* Stereo frustum params.  */
  44.  
  45. void init( void );
  46. void reshape( int width, int height );
  47. void draw( void );
  48. void idle();
  49. void Key(unsigned char key, int x, int y);
  50.  
  51. typedef union __attribute__((packed))
  52. {
  53.     uint32_t val;
  54.     struct
  55.     {
  56.         uint8_t   state;
  57.         uint8_t   code;
  58.         uint16_t  ctrl_key;
  59.     };
  60. }oskey_t;
  61.  
  62. static inline oskey_t get_key(void)
  63. {
  64.     oskey_t val;
  65.     __asm__ __volatile__(
  66.     "int $0x40"
  67.     :"=eax"(val)
  68.     :"a"(2));
  69.     return val;
  70. }
  71.  
  72.  
  73. struct blit_call
  74. {
  75.     int dstx;
  76.     int dsty;
  77.     int w;
  78.     int h;
  79.  
  80.     int srcx;
  81.     int srcy;
  82.     int srcw;
  83.     int srch;
  84.  
  85.     unsigned char *bitmap;
  86.     int   stride;
  87. };
  88.  
  89. static inline uint32_t wait_os_event(int time)
  90. {
  91.     uint32_t val;
  92.     __asm__ __volatile__(
  93.     "int $0x40"
  94.     :"=a"(val)
  95.     :"a"(23),"b"(time));
  96.     return val;
  97. };
  98.  
  99. static inline uint32_t get_os_button()
  100. {
  101.     uint32_t val;
  102.     __asm__ __volatile__(
  103.     "int $0x40"
  104.     :"=a"(val)
  105.     :"a"(17));
  106.     return val>>8;
  107. };
  108.  
  109. static inline void DrawWindow(int x, int y, int w, int h, char *name,
  110.                        uint32_t workcolor, uint32_t style)
  111. {
  112.  
  113.     __asm__ __volatile__(
  114.     "int $0x40"
  115.     ::"a"(0),
  116.       "b"((x << 16) | (w & 0xFFFF)),
  117.       "c"((y << 16) | (h & 0xFFFF)),
  118.       "d"((style << 24) | (workcolor & 0xFFFFFF)),
  119.       "D"(name));
  120. };
  121.  
  122. static inline void Blit(void *bitmap, int dst_x, int dst_y,
  123.                         int src_x, int src_y, int w, int h,
  124.                         int src_w, int src_h, int stride)
  125. {
  126.     volatile struct blit_call bc;
  127.  
  128.     bc.dstx = dst_x;
  129.     bc.dsty = dst_y;
  130.     bc.w    = w;
  131.     bc.h    = h;
  132.     bc.srcx = src_x;
  133.     bc.srcy = src_y;
  134.     bc.srcw = src_w;
  135.     bc.srch = src_h;
  136.     bc.stride = stride;
  137.     bc.bitmap = bitmap;
  138.  
  139.     __asm__ __volatile__(
  140.     "int $0x40"
  141.     ::"a"(73),"b"(0),"c"(&bc.dstx));
  142.  
  143. };
  144.  
  145.  
  146. #define XK_Left      176
  147. #define XK_Right    179
  148. #define XK_Up        178
  149. #define XK_Down    177
  150.  
  151.  
  152. int main(int argc, char *argv[])
  153. {
  154.    OSMesaContext ctx;
  155.    void *buffer;
  156.    char *filename = NULL;
  157.    int ev;
  158.    int repeat=1;
  159.  
  160.     /* Create an RGBA-mode context */
  161.    /* specify Z, stencil, accum sizes */
  162.  
  163.    ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL );
  164.    if (!ctx) {
  165.       printf("OSMesaCreateContext failed!\n");
  166.       return 0;
  167.    }
  168.  
  169.    /* Allocate the image buffer */
  170.    buffer = malloc( Width * Height * 4 * sizeof(GLubyte) );
  171.    if (!buffer) {
  172.       printf("Alloc image buffer failed!\n");
  173.       return 0;
  174.    }
  175.  
  176.  //  __asm__ __volatile__("int3");
  177.  
  178.    /* Bind the buffer to the context and make it current */
  179.    if (!OSMesaMakeCurrent( ctx, buffer, GL_UNSIGNED_BYTE, Width, Height )) {
  180.       printf("OSMesaMakeCurrent failed!\n");
  181.       return 0;
  182.    }
  183.  
  184.    {
  185.       int z, s, a;
  186.       glGetIntegerv(GL_DEPTH_BITS, &z);
  187.       glGetIntegerv(GL_STENCIL_BITS, &s);
  188.       glGetIntegerv(GL_ACCUM_RED_BITS, &a);
  189.       printf("Depth=%d Stencil=%d Accum=%d\n", z, s, a);
  190.    }
  191.  
  192.     reshape(Width, Height);
  193.  
  194.     init();
  195.     draw();
  196.  
  197.    printf("all done\n");
  198.  
  199.     DrawWindow(10, 10, Width+9, Height+26, "OpenGL Engine Demo", 0x000000, 0x74);
  200.     Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
  201.  
  202.     while(repeat)
  203.     {
  204.         oskey_t   key;
  205.  
  206.         ev = wait_os_event(1);
  207.         switch(ev)
  208.         {
  209.             case 1:
  210.                 DrawWindow(10, 10, Width+9, Width+26, NULL, 0x000000,0x74);
  211.                 Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
  212.                 continue;
  213.  
  214.             case 2:
  215.                 key = get_key();
  216.                 Key(key.code, 0, 0);
  217.                 draw();
  218.                 Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
  219.                 continue;
  220.  
  221.             case 3:
  222.                 if(get_os_button()==1)
  223.                     repeat=0;
  224.                     continue;
  225.         };
  226.  
  227.         idle();
  228.  
  229. //        angle += 70.0 * 0.05;  /* 70 degrees per second */
  230. //        if (angle > 3600.0)
  231. //            angle -= 3600.0;
  232.         draw();
  233.         Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
  234.     };
  235.  
  236.    /* free the image buffer */
  237.    free( buffer );
  238.  
  239.    /* destroy the context */
  240.    OSMesaDestroyContext( ctx );
  241.  
  242.    return 0;
  243. }
  244.  
  245. void exit(int code)
  246. {
  247.     _exit(code);
  248.  
  249. }
  250.  
  251. #if 0
  252. static char *FragProgFile = "CH11-toyball.frag";
  253. static char *VertProgFile = "CH11-toyball.vert";
  254.  
  255. /* program/shader objects */
  256. static GLuint fragShader;
  257. static GLuint vertShader;
  258. static GLuint program;
  259.  
  260.  
  261. static struct uniform_info Uniforms[] = {
  262.    { "LightDir",    1, GL_FLOAT_VEC4, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 },
  263.    { "HVector",     1, GL_FLOAT_VEC4, { 0.32506, 0.32506, 0.88808, 0.0 }, -1 },
  264.    { "BallCenter",  1, GL_FLOAT_VEC4, { 0.0, 0.0, 0.0, 1.0 }, -1 },
  265.    { "SpecularColor", 1, GL_FLOAT_VEC4, { 0.4, 0.4, 0.4, 60.0 }, -1 },
  266.    { "Red",         1, GL_FLOAT_VEC4, { 0.6, 0.0, 0.0, 1.0 }, -1 },
  267.    { "Blue",        1, GL_FLOAT_VEC4, { 0.0, 0.3, 0.6, 1.0 }, -1 },
  268.    { "Yellow",      1, GL_FLOAT_VEC4, { 0.6, 0.5, 0.0, 1.0 }, -1 },
  269.    { "HalfSpace0",  1, GL_FLOAT_VEC4, { 1.0, 0.0, 0.0, 0.2 }, -1 },
  270.    { "HalfSpace1",  1, GL_FLOAT_VEC4, { 0.309016994, 0.951056516, 0.0, 0.2 }, -1 },
  271.    { "HalfSpace2",  1, GL_FLOAT_VEC4, { -0.809016994, 0.587785252, 0.0, 0.2 }, -1 },
  272.    { "HalfSpace3",  1, GL_FLOAT_VEC4, { -0.809016994, -0.587785252, 0.0, 0.2 }, -1 },
  273.    { "HalfSpace4",  1, GL_FLOAT_VEC4, { 0.309116994, -0.951056516, 0.0, 0.2 }, -1 },
  274.    { "InOrOutInit", 1, GL_FLOAT, { -3.0, 0, 0, 0 }, -1 },
  275.    { "StripeWidth", 1, GL_FLOAT, {  0.3, 0, 0, 0 }, -1 },
  276.    { "FWidth",      1, GL_FLOAT, { 0.005, 0, 0, 0 }, -1 },
  277.    END_OF_UNIFORMS
  278. };
  279.  
  280. static GLint win = 0;
  281. static GLboolean Anim = GL_FALSE;
  282. static GLfloat TexRot = 0.0;
  283. static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
  284.  
  285.  
  286. void Idle(void)
  287. {
  288.    TexRot += 2.0;
  289.    if (TexRot > 360.0)
  290.       TexRot -= 360.0;
  291. }
  292.  
  293.  
  294. void draw(void)
  295. {
  296.    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  297.  
  298.    glPushMatrix();
  299.    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  300.    glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  301.    glRotatef(zRot, 0.0f, 0.0f, 1.0f);
  302.  
  303.    glMatrixMode(GL_TEXTURE);
  304.    glLoadIdentity();
  305.    glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
  306.    glMatrixMode(GL_MODELVIEW);
  307.  
  308.    glutSolidSphere(2.0, 20, 10);
  309.  
  310.    glPopMatrix();
  311.  
  312.  }
  313.  
  314.  
  315. void
  316. reshape(int width, int height)
  317. {
  318.    glViewport(0, 0, width, height);
  319.    glMatrixMode(GL_PROJECTION);
  320.    glLoadIdentity();
  321.    glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
  322.    glMatrixMode(GL_MODELVIEW);
  323.    glLoadIdentity();
  324.    glTranslatef(0.0f, 0.0f, -15.0f);
  325. }
  326.  
  327.  
  328. static void
  329. CleanUp(void)
  330. {
  331.    glDeleteShader(fragShader);
  332.    glDeleteShader(vertShader);
  333.    glDeleteProgram(program);
  334.    glutDestroyWindow(win);
  335. }
  336.  
  337.  
  338.  
  339. void init(void)
  340. {
  341. //   if (!ShadersSupported())
  342. //      exit(1);
  343.  
  344.    vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertProgFile);
  345.    fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragProgFile);
  346.    program = LinkShaders(vertShader, fragShader);
  347.  
  348.    glUseProgram(program);
  349.  
  350.    SetUniformValues(program, Uniforms);
  351.    PrintUniforms(Uniforms);
  352.  
  353.    assert(glGetError() == 0);
  354.  
  355.    glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
  356.  
  357.    glEnable(GL_DEPTH_TEST);
  358.  
  359.    glColor3f(1, 0, 0);
  360. }
  361. #endif
  362.  
  363.  
  364. #if 0
  365. static float Zrot = 0.0;
  366.  
  367. void draw( void )
  368. {
  369.    glClearColor(0.3, 0.3, 0.3, 1);
  370.    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  371.  
  372.    glEnable(GL_VERTEX_PROGRAM_NV);
  373.  
  374.    glLoadIdentity();
  375.    glRotatef(Zrot, 0, 0, 1);
  376.  
  377.    glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW, GL_IDENTITY_NV);
  378.    glPushMatrix();
  379.  
  380.    glVertexAttrib3fNV(3, 1, 0.5, 0.25);
  381.    glBegin(GL_TRIANGLES);
  382. #if 1
  383.    glVertexAttrib3fNV(3, 1.0, 0.0, 0.0);
  384.    glVertexAttrib2fNV(0, -0.5, -0.5);
  385.    glVertexAttrib3fNV(3, 0.0, 1.0, 0.0);
  386.    glVertexAttrib2fNV(0, 0.5, -0.5);
  387.    glVertexAttrib3fNV(3, 0.0, 0.0, 1.0);
  388.    glVertexAttrib2fNV(0, 0,  0.5);
  389. #else
  390.    glVertex2f( -1, -1);
  391.    glVertex2f( 1, -1);
  392.    glVertex2f( 0,  1);
  393. #endif
  394.    glEnd();
  395.  
  396.    glPopMatrix();
  397.  
  398.  }
  399.  
  400.  
  401. void reshape( int width, int height )
  402. {
  403.    glViewport( 0, 0, width, height );
  404.    glMatrixMode( GL_PROJECTION );
  405.    glLoadIdentity();
  406.    /*   glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
  407.    glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0 );
  408.    glMatrixMode( GL_MODELVIEW );
  409.    glLoadIdentity();
  410.    /*glTranslatef( 0.0, 0.0, -15.0 );*/
  411. }
  412.  
  413. void idle()
  414. {
  415.     Zrot-=4.0;
  416. };
  417.  
  418. void init( void )
  419. {
  420.    static const char *prog1 =
  421.       "!!VP1.0\n"
  422.       "MOV  o[COL0], v[COL0];\n"
  423. #if 0
  424.       "MOV   o[HPOS], v[OPOS];\n"
  425. #else
  426.       "DP4  o[HPOS].x, v[OPOS], c[0];\n"
  427.       "DP4  o[HPOS].y, v[OPOS], c[1];\n"
  428.       "DP4  o[HPOS].z, v[OPOS], c[2];\n"
  429.       "DP4  o[HPOS].w, v[OPOS], c[3];\n"
  430. #endif
  431.       "END\n";
  432.  
  433. //   if (!glutExtensionSupported("GL_NV_vertex_program")) {
  434. //      printf("Sorry, this program requires GL_NV_vertex_program\n");
  435.  //     exit(1);
  436.  //  }
  437.  
  438.    glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
  439.                    strlen(prog1),
  440.                    (const GLubyte *) prog1);
  441.    assert(glIsProgramNV(1));
  442.  
  443.    glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
  444.  
  445.    printf("glGetError = %x\n", (int) glGetError());
  446. }
  447. #endif
  448.  
  449. #ifndef M_PI
  450. #define M_PI 3.14159265358979323846
  451. #endif
  452.  
  453. #define DEG_TO_RAD(DEG)  ((DEG) * M_PI / 180.0)
  454.  
  455. #define TEXTURE_FILE "reflect.rgb"
  456.  
  457. /* Target engine speed: */
  458. const int RPM = 100.0;
  459.  
  460. static int Win = 0;
  461.  
  462.  
  463. /**
  464.  * Engine description.
  465.  */
  466. typedef struct
  467. {
  468.    const char *Name;
  469.    int Pistons;
  470.    int Cranks;
  471.    float V_Angle;
  472.    float PistonRadius;
  473.    float PistonHeight;
  474.    float WristPinRadius;
  475.    float Throw;
  476.    float CrankPlateThickness;
  477.    float CrankPinRadius;
  478.    float CrankJournalRadius;
  479.    float CrankJournalLength;
  480.    float ConnectingRodLength;
  481.    float ConnectingRodThickness;
  482.    /* display list IDs */
  483.    GLuint CrankList;
  484.    GLuint ConnRodList;
  485.    GLuint PistonList;
  486.    GLuint BlockList;
  487. } Engine;
  488.  
  489.  
  490. typedef struct
  491. {
  492.    float CurQuat[4];
  493.    float Distance;
  494.    /* When mouse is moving: */
  495.    GLboolean Rotating, Translating;
  496.    GLint StartX, StartY;
  497.    float StartDistance;
  498. } ViewInfo;
  499.  
  500.  
  501. typedef enum
  502. {
  503.    LIT,
  504.    WIREFRAME,
  505.    TEXTURED
  506. } RenderMode;
  507.  
  508.  
  509. typedef struct
  510. {
  511.    RenderMode Mode;
  512.    GLboolean Anim;
  513.    GLboolean Wireframe;
  514.    GLboolean Blend;
  515.    GLboolean Antialias;
  516.    GLboolean Texture;
  517.    GLboolean UseLists;
  518.    GLboolean DrawBox;
  519.    GLboolean ShowInfo;
  520.    GLboolean ShowBlock;
  521. } RenderInfo;
  522.  
  523.  
  524. static GLUquadric *Q;
  525.  
  526. static GLfloat Theta = 0.0;
  527.  
  528. static const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
  529. static const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
  530. static const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
  531. static const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 };
  532.  
  533. static GLuint TextureObj;
  534. static GLint WinWidth = 800, WinHeight = 500;
  535.  
  536. static ViewInfo View;
  537. static RenderInfo Render;
  538.  
  539. void build_rotmatrix(float m[4][4], const float q[4])
  540. {
  541.     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
  542.     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
  543.     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
  544.     m[0][3] = 0.0;
  545.  
  546.     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
  547.     m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
  548.     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
  549.     m[1][3] = 0.0;
  550.  
  551.     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
  552.     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
  553.     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
  554.     m[2][3] = 0.0;
  555.  
  556.     m[3][0] = 0.0;
  557.     m[3][1] = 0.0;
  558.     m[3][2] = 0.0;
  559.     m[3][3] = 1.0;
  560. }
  561.  
  562.  
  563. #define NUM_ENGINES 3
  564. static Engine Engines[NUM_ENGINES] =
  565. {
  566.    {
  567.       "V-6",
  568.       6,    /* Pistons */
  569.       3,    /* Cranks */
  570.       90.0, /* V_Angle */
  571.       0.5,  /* PistonRadius */
  572.       0.6,  /* PistonHeight */
  573.       0.1,  /* WristPinRadius */
  574.       0.5,  /* Throw */
  575.       0.2,  /* CrankPlateThickness */
  576.       0.25, /* CrankPinRadius */
  577.       0.3,  /* CrankJournalRadius */
  578.       0.4,  /* CrankJournalLength */
  579.       1.5,  /* ConnectingRodLength */
  580.       0.1,  /* ConnectingRodThickness */
  581.       0,    /* CrankList */
  582.       0,    /* ConnRodList */
  583.       0,    /* PistonList */
  584.       0     /* BlockList */
  585.    },
  586.    {
  587.       "Inline-4",
  588.       4,    /* Pistons */
  589.       4,    /* Cranks */
  590.       0.0,  /* V_Angle */
  591.       0.5,  /* PistonRadius */
  592.       0.6,  /* PistonHeight */
  593.       0.1,  /* WristPinRadius */
  594.       0.5,  /* Throw */
  595.       0.2,  /* CrankPlateThickness */
  596.       0.25, /* CrankPinRadius */
  597.       0.3,  /* CrankJournalRadius */
  598.       0.4,  /* CrankJournalLength */
  599.       1.5,  /* ConnectingRodLength */
  600.       0.1,  /* ConnectingRodThickness */
  601.       0,    /* CrankList */
  602.       0,    /* ConnRodList */
  603.       0,    /* PistonList */
  604.       0     /* BlockList */
  605.    },
  606.    {
  607.       "Boxer-6",
  608.       6,    /* Pistons */
  609.       3,    /* Cranks */
  610.       180.0,/* V_Angle */
  611.       0.5,  /* PistonRadius */
  612.       0.6,  /* PistonHeight */
  613.       0.1,  /* WristPinRadius */
  614.       0.5,  /* Throw */
  615.       0.2,  /* CrankPlateThickness */
  616.       0.25, /* CrankPinRadius */
  617.       0.3,  /* CrankJournalRadius */
  618.       0.4,  /* CrankJournalLength */
  619.       1.5,  /* ConnectingRodLength */
  620.       0.1,  /* ConnectingRodThickness */
  621.       0,    /* CrankList */
  622.       0,    /* ConnRodList */
  623.       0,    /* PistonList */
  624.       0     /* BlockList */
  625.    }
  626. };
  627.  
  628. static int CurEngine = 0;
  629.  
  630.  
  631.  
  632. static void
  633. InitViewInfo(ViewInfo *view)
  634. {
  635.    view->Rotating = GL_FALSE;
  636.    view->Translating = GL_FALSE;
  637.    view->StartX = view->StartY = 0;
  638.    view->Distance = 12.0;
  639.    view->StartDistance = 0.0;
  640.    view->CurQuat[0] = -0.194143;
  641.    view->CurQuat[1] = 0.507848;
  642.    view->CurQuat[2] = 0.115245;
  643.    view->CurQuat[3] = 0.831335;
  644. }
  645.  
  646.  
  647. static void
  648. InitRenderInfo(RenderInfo *render)
  649. {
  650.    render->Mode = LIT;
  651.    render->Anim = GL_TRUE;
  652.    render->Wireframe = GL_FALSE;
  653.    render->Blend = GL_FALSE;
  654.    render->Antialias = GL_FALSE;
  655.    render->Texture = GL_FALSE;
  656.    render->DrawBox = GL_FALSE;
  657.    render->ShowInfo = GL_TRUE;
  658.    render->ShowBlock = GL_FALSE;
  659.    render->UseLists = GL_FALSE;
  660. }
  661.  
  662.  
  663. /**
  664.  * Set GL for given rendering mode.
  665.  */
  666. static void
  667. SetRenderState(RenderMode mode)
  668. {
  669.    static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 };
  670.    static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 };
  671.  
  672.    /* defaults */
  673.    glDisable(GL_LIGHTING);
  674.    glDisable(GL_TEXTURE_2D);
  675.    glDisable(GL_BLEND);
  676.    glDisable(GL_LINE_SMOOTH);
  677.    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  678.    glDisable(GL_TEXTURE_GEN_S);
  679.    glDisable(GL_TEXTURE_GEN_T);
  680.    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2);
  681.  
  682.    switch (mode) {
  683.    case LIT:
  684.       glEnable(GL_LIGHTING);
  685.       break;
  686.    case WIREFRAME:
  687.       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  688.       glEnable(GL_LINE_SMOOTH);
  689.       glEnable(GL_BLEND);
  690.       glLineWidth(1.5);
  691.       break;
  692.    case TEXTURED:
  693.       glEnable(GL_LIGHTING);
  694.       glEnable(GL_TEXTURE_2D);
  695.       glEnable(GL_TEXTURE_GEN_S);
  696.       glEnable(GL_TEXTURE_GEN_T);
  697.       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4);
  698.       break;
  699.    default:
  700.       ;
  701.    }
  702. }
  703.  
  704.  
  705. /**
  706.  * Animate the engine parts.
  707.  */
  708. void idle(void)
  709. {
  710.    /* convert degrees per millisecond to RPM: */
  711.    const float m = 360.0 / 1000.0 / 60.0;
  712.    static GLfloat t;
  713.    t+=10;
  714.    Theta = ((int) (t * RPM * m)) % 360;
  715.  
  716. }
  717.  
  718.  
  719. /**
  720.  * Compute piston's position along its stroke.
  721.  */
  722. static float
  723. PistonStrokePosition(float throwDist, float crankAngle, float connRodLength)
  724. {
  725.    float x = throwDist * cos(DEG_TO_RAD(crankAngle));
  726.    float y = throwDist * sin(DEG_TO_RAD(crankAngle));
  727.    float pos = y + sqrt(connRodLength * connRodLength - x * x);
  728.    return pos;
  729. }
  730.  
  731.  
  732. /**
  733.  * Compute position of nth piston along the crankshaft.
  734.  */
  735. static float
  736. PistonShaftPosition(const Engine *eng, int piston)
  737. {
  738.    const int i = piston / (eng->Pistons / eng->Cranks);
  739.    float z;
  740.    assert(piston < eng->Pistons);
  741.    z = 1.5 * eng->CrankJournalLength + eng->CrankPlateThickness
  742.       + i * (2.0 * (eng->CrankJournalLength + eng->CrankPlateThickness));
  743.    if (eng->Pistons > eng->Cranks) {
  744.       if (piston & 1)
  745.          z += eng->ConnectingRodThickness;
  746.       else
  747.          z -= eng->ConnectingRodThickness;
  748.    }
  749.    return z;
  750. }
  751.  
  752.  
  753. /**
  754.  * Compute distance between two adjacent pistons
  755.  */
  756. static float
  757. PistonSpacing(const Engine *eng)
  758. {
  759.    const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  760.    const float z0 = PistonShaftPosition(eng, 0);
  761.    const float z1 = PistonShaftPosition(eng, pistonsPerCrank);
  762.    return z1 - z0;
  763. }
  764.  
  765.  
  766. /**
  767.  * (x0, y0) = position of big end on crankshaft
  768.  * (x1, y1) = position of small end on piston
  769.  */
  770. static void
  771. ComputeConnectingRodPosition(float throwDist, float crankAngle,
  772.                              float connRodLength,
  773.                              float *x0, float *y0, float *x1, float *y1)
  774. {
  775.    *x0 = throwDist * cos(DEG_TO_RAD(crankAngle));
  776.    *y0 = throwDist * sin(DEG_TO_RAD(crankAngle));
  777.    *x1 = 0.0;
  778.    *y1 = PistonStrokePosition(throwDist, crankAngle, connRodLength);
  779. }
  780.  
  781.  
  782. /**
  783.  * Compute total length of the crankshaft.
  784.  */
  785. static float
  786. CrankshaftLength(const Engine *eng)
  787. {
  788.    float len = (eng->Cranks * 2 + 1) * eng->CrankJournalLength
  789.              + 2 * eng->Cranks * eng->CrankPlateThickness;
  790.    return len;
  791. }
  792.  
  793.  
  794. /**
  795.  * Draw a piston.
  796.  * Axis of piston = Z axis.  Wrist pin is centered on (0, 0, 0).
  797.  */
  798. static void
  799. DrawPiston(const Engine *eng)
  800. {
  801.    const int slices = 30, stacks = 4, loops = 4;
  802.    const float innerRadius = 0.9 * eng->PistonRadius;
  803.    const float innerHeight = eng->PistonHeight - 0.15;
  804.    const float wristPinLength = 1.8 * eng->PistonRadius;
  805.  
  806.    assert(Q);
  807.  
  808.    glPushMatrix();
  809.    glTranslatef(0, 0, -1.1 * eng->WristPinRadius);
  810.  
  811.    gluQuadricOrientation(Q, GLU_INSIDE);
  812.  
  813.    /* bottom rim */
  814.    gluDisk(Q, innerRadius, eng->PistonRadius, slices, 1/*loops*/);
  815.  
  816.    /* inner cylinder */
  817.    gluCylinder(Q, innerRadius, innerRadius, innerHeight, slices, stacks);
  818.  
  819.    /* inside top */
  820.    glPushMatrix();
  821.    glTranslatef(0, 0, innerHeight);
  822.    gluDisk(Q, 0, innerRadius, slices, loops);
  823.    glPopMatrix();
  824.  
  825.    gluQuadricOrientation(Q, GLU_OUTSIDE);
  826.  
  827.    /* outer cylinder */
  828.    gluCylinder(Q, eng->PistonRadius, eng->PistonRadius, eng->PistonHeight,
  829.                slices, stacks);
  830.  
  831.    /* top */
  832.    glTranslatef(0, 0, eng->PistonHeight);
  833.    gluDisk(Q, 0, eng->PistonRadius, slices, loops);
  834.  
  835.    glPopMatrix();
  836.  
  837.    /* wrist pin */
  838.    glPushMatrix();
  839.    glTranslatef(0, 0.5 * wristPinLength, 0.0);
  840.    glRotatef(90, 1, 0, 0);
  841.    gluCylinder(Q, eng->WristPinRadius, eng->WristPinRadius, wristPinLength,
  842.                slices, stacks);
  843.    glPopMatrix();
  844. }
  845.  
  846.  
  847. /**
  848.  * Draw piston at particular position.
  849.  */
  850. static void
  851. DrawPositionedPiston(const Engine *eng, float crankAngle)
  852. {
  853.    const float pos = PistonStrokePosition(eng->Throw, crankAngle,
  854.                                           eng->ConnectingRodLength);
  855.    glPushMatrix();
  856.       glRotatef(-90, 1, 0, 0);
  857.       glTranslatef(0, 0, pos);
  858.       if (eng->PistonList)
  859.          glCallList(eng->PistonList);
  860.       else
  861.          DrawPiston(eng);
  862.    glPopMatrix();
  863. }
  864.  
  865.  
  866. /**
  867.  * Draw connector plate.  Used for crankshaft and connecting rods.
  868.  */
  869. static void
  870. DrawConnector(float length, float thickness,
  871.               float bigEndRadius, float smallEndRadius)
  872. {
  873.    const float bigRadius = 1.2 * bigEndRadius;
  874.    const float smallRadius = 1.2 * smallEndRadius;
  875.    const float z0 = -0.5 * thickness, z1 = -z0;
  876.    GLfloat points[36][2], normals[36][2];
  877.    int i;
  878.  
  879.    /* compute vertex locations, normals */
  880.    for (i = 0; i < 36; i++) {
  881.       const int angle = i * 10;
  882.       float x = cos(DEG_TO_RAD(angle));
  883.       float y = sin(DEG_TO_RAD(angle));
  884.       normals[i][0] = x;
  885.       normals[i][1] = y;
  886.       if (angle >= 0 && angle <= 180) {
  887.          x *= smallRadius;
  888.          y = y * smallRadius + length;
  889.       }
  890.       else {
  891.          x *= bigRadius;
  892.          y *= bigRadius;
  893.       }
  894.       points[i][0] = x;
  895.       points[i][1] = y;
  896.    }
  897.  
  898.    /* front face */
  899.    glNormal3f(0, 0, 1);
  900.    glBegin(GL_POLYGON);
  901.    for (i = 0; i < 36; i++) {
  902.       glVertex3f(points[i][0], points[i][1], z1);
  903.    }
  904.    glEnd();
  905.  
  906.    /* back face */
  907.    glNormal3f(0, 0, -1);
  908.    glBegin(GL_POLYGON);
  909.    for (i = 0; i < 36; i++) {
  910.       glVertex3f(points[35-i][0], points[35-i][1], z0);
  911.    }
  912.    glEnd();
  913.  
  914.    /* edge */
  915.    glBegin(GL_QUAD_STRIP);
  916.    for (i = 0; i <= 36; i++) {
  917.       const int j = i % 36;
  918.       glNormal3f(normals[j][0], normals[j][1], 0);
  919.       glVertex3f(points[j][0], points[j][1], z1);
  920.       glVertex3f(points[j][0], points[j][1], z0);
  921.    }
  922.    glEnd();
  923. }
  924.  
  925.  
  926. /**
  927.  * Draw a crankshaft.  Shaft lies along +Z axis, starting at zero.
  928.  */
  929. static void
  930. DrawCrankshaft(const Engine *eng)
  931. {
  932.    const int slices = 20, stacks = 2;
  933.    const int n = eng->Cranks * 4 + 1;
  934.    const float phiStep = 360 / eng->Cranks;
  935.    float phi = -90.0;
  936.    int i;
  937.    float z = 0.0;
  938.  
  939.    for (i = 0; i < n; i++) {
  940.       glPushMatrix();
  941.       glTranslatef(0, 0, z);
  942.       if (i & 1) {
  943.          /* draw a crank plate */
  944.          glRotatef(phi, 0, 0, 1);
  945.          glTranslatef(0, 0, 0.5 * eng->CrankPlateThickness);
  946.          DrawConnector(eng->Throw, eng->CrankPlateThickness,
  947.                        eng->CrankJournalRadius, eng->CrankPinRadius);
  948.          z += 0.2;
  949.          if (i % 4 == 3)
  950.             phi += phiStep;
  951.       }
  952.       else if (i % 4 == 0) {
  953.          /* draw crank journal segment */
  954.          gluCylinder(Q, eng->CrankJournalRadius, eng->CrankJournalRadius,
  955.                      eng->CrankJournalLength, slices, stacks);
  956.          z += eng->CrankJournalLength;
  957.       }
  958.       else if (i % 4 == 2) {
  959.          /* draw crank pin segment */
  960.          glRotatef(phi, 0, 0, 1);
  961.          glTranslatef(0, eng->Throw, 0);
  962.          gluCylinder(Q, eng->CrankPinRadius, eng->CrankPinRadius,
  963.                      eng->CrankJournalLength, slices, stacks);
  964.          z += eng->CrankJournalLength;
  965.       }
  966.       glPopMatrix();
  967.    }
  968. }
  969.  
  970.  
  971. /**
  972.  * Draw crankshaft at a particular rotation.
  973.  * \param crankAngle  current crankshaft rotation, in radians
  974.  */
  975. static void
  976. DrawPositionedCrankshaft(const Engine *eng, float crankAngle)
  977. {
  978.    glPushMatrix();
  979.       glRotatef(crankAngle, 0, 0, 1);
  980.       if (eng->CrankList)
  981.          glCallList(eng->CrankList);
  982.       else
  983.          DrawCrankshaft(eng);
  984.    glPopMatrix();
  985. }
  986.  
  987.  
  988. /**
  989.  * Draw a connecting rod at particular position.
  990.  * \param eng  description of connecting rod to draw
  991.  * \param crankAngle  current crankshaft rotation, in radians
  992.  */
  993. static void
  994. DrawPositionedConnectingRod(const Engine *eng, float crankAngle)
  995. {
  996.    float x0, y0, x1, y1;
  997.    float d, phi;
  998.  
  999.    ComputeConnectingRodPosition(eng->Throw, crankAngle,
  1000.                                 eng->ConnectingRodLength,
  1001.                                 &x0, &y0, &x1, &y1);
  1002.    d = sqrt(eng->ConnectingRodLength * eng->ConnectingRodLength - x0 * x0);
  1003.    phi = atan(x0 / d) * 180.0 / M_PI;
  1004.  
  1005.    glPushMatrix();
  1006.       glTranslatef(x0, y0, 0);
  1007.       glRotatef(phi, 0, 0, 1);
  1008.       if (eng->ConnRodList)
  1009.          glCallList(eng->ConnRodList);
  1010.       else
  1011.          DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
  1012.                        eng->CrankPinRadius, eng->WristPinRadius);
  1013.    glPopMatrix();
  1014. }
  1015.  
  1016.  
  1017. /**
  1018.  * Draw a square with a hole in middle.
  1019.  */
  1020. static void
  1021. SquareWithHole(float squareSize, float holeRadius)
  1022. {
  1023.    int i;
  1024.    glBegin(GL_QUAD_STRIP);
  1025.    glNormal3f(0, 0, 1);
  1026.    for (i = 0; i <= 360; i += 5) {
  1027.       const float x1 = holeRadius * cos(DEG_TO_RAD(i));
  1028.       const float y1 = holeRadius * sin(DEG_TO_RAD(i));
  1029.       float x2 = 0.0F, y2 = 0.0F;
  1030.       if (i > 315 || i <= 45) {
  1031.          x2 = squareSize;
  1032.          y2 = squareSize * tan(DEG_TO_RAD(i));
  1033.       }
  1034.       else if (i > 45 && i <= 135) {
  1035.          x2 = -squareSize * tan(DEG_TO_RAD(i - 90));
  1036.          y2 = squareSize;
  1037.       }
  1038.       else if (i > 135 && i <= 225) {
  1039.          x2 = -squareSize;
  1040.          y2 = -squareSize * tan(DEG_TO_RAD(i-180));
  1041.       }
  1042.       else if (i > 225 && i <= 315) {
  1043.          x2 = squareSize * tan(DEG_TO_RAD(i - 270));
  1044.          y2 = -squareSize;
  1045.       }
  1046.       glVertex2f(x1, y1); /* inner circle */
  1047.       glVertex2f(x2, y2); /* outer square */
  1048.    }
  1049.    glEnd();
  1050. }
  1051.  
  1052.  
  1053. /**
  1054.  * Draw block with hole through middle.
  1055.  * Hole is centered on Z axis.
  1056.  * Bottom of block is at z=0, top of block is at z = blockHeight.
  1057.  * index is in [0, count - 1] to determine which block faces are drawn.
  1058.  */
  1059. static void
  1060. DrawBlockWithHole(float blockSize, float blockHeight, float holeRadius,
  1061.                   int index, int count)
  1062. {
  1063.    const int slices = 30, stacks = 4;
  1064.    const float x = blockSize;
  1065.    const float y = blockSize;
  1066.    const float z0 = 0;
  1067.    const float z1 = blockHeight;
  1068.  
  1069.    assert(index < count);
  1070.    assert(Q);
  1071.    gluQuadricOrientation(Q, GLU_INSIDE);
  1072.  
  1073.    glBegin(GL_QUADS);
  1074.    /* +X face */
  1075.    glNormal3f(1, 0, 0);
  1076.    glVertex3f( x, -y, z0);
  1077.    glVertex3f( x, y, z0);
  1078.    glVertex3f( x, y, z1);
  1079.    glVertex3f( x, -y, z1);
  1080.    /* -X face */
  1081.    glNormal3f(-1, 0, 0);
  1082.    glVertex3f(-x, -y, z1);
  1083.    glVertex3f(-x, y, z1);
  1084.    glVertex3f(-x, y, z0);
  1085.    glVertex3f(-x, -y, z0);
  1086.    if (index == 0) {
  1087.       /* +Y face */
  1088.       glNormal3f(0, 1, 0);
  1089.       glVertex3f(-x, y, z1);
  1090.       glVertex3f( x, y, z1);
  1091.       glVertex3f( x, y, z0);
  1092.       glVertex3f(-x, y, z0);
  1093.    }
  1094.    if (index == count - 1) {
  1095.       /* -Y face */
  1096.       glNormal3f(0, -1, 0);
  1097.       glVertex3f(-x, -y, z0);
  1098.       glVertex3f( x, -y, z0);
  1099.       glVertex3f( x, -y, z1);
  1100.       glVertex3f(-x, -y, z1);
  1101.    }
  1102.    glEnd();
  1103.  
  1104.    /* cylinder / hole */
  1105.    gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks);
  1106.  
  1107.    /* face at z0 */
  1108.    glPushMatrix();
  1109.    glRotatef(180, 1, 0, 0);
  1110.    SquareWithHole(blockSize, holeRadius);
  1111.    glPopMatrix();
  1112.  
  1113.    /* face at z1 */
  1114.    glTranslatef(0, 0, z1);
  1115.    SquareWithHole(blockSize, holeRadius);
  1116.  
  1117.    gluQuadricOrientation(Q, GLU_OUTSIDE);
  1118. }
  1119.  
  1120.  
  1121. /**
  1122.  * Draw the engine block.
  1123.  */
  1124. static void
  1125. DrawEngineBlock(const Engine *eng)
  1126. {
  1127.    const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight;
  1128.    const float cylRadius = 1.01 * eng->PistonRadius;
  1129.    const float blockSize = 0.5 * PistonSpacing(eng);
  1130.    const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  1131.    int i;
  1132.  
  1133.    for (i = 0; i < eng->Pistons; i++) {
  1134.       const float z = PistonShaftPosition(eng, i);
  1135.       const int crank = i / pistonsPerCrank;
  1136.       int k;
  1137.  
  1138.       glPushMatrix();
  1139.          glTranslatef(0, 0, z);
  1140.  
  1141.          /* additional rotation for kth piston per crank */
  1142.          k = i % pistonsPerCrank;
  1143.          glRotatef(k * -eng->V_Angle, 0, 0, 1);
  1144.  
  1145.          /* the block */
  1146.          glRotatef(-90, 1, 0, 0);
  1147.          glTranslatef(0, 0, eng->Throw * 2);
  1148.          DrawBlockWithHole(blockSize, blockHeight, cylRadius,
  1149.                            crank, eng->Cranks);
  1150.       glPopMatrix();
  1151.    }
  1152. }
  1153.  
  1154.  
  1155. /**
  1156.  * Generate display lists for engine parts.
  1157.  */
  1158. static void
  1159. GenerateDisplayLists(Engine *eng)
  1160. {
  1161.    eng->CrankList = glGenLists(1);
  1162.    glNewList(eng->CrankList, GL_COMPILE);
  1163.    DrawCrankshaft(eng);
  1164.    glEndList();
  1165.  
  1166.    eng->ConnRodList = glGenLists(1);
  1167.    glNewList(eng->ConnRodList, GL_COMPILE);
  1168.    DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
  1169.                  eng->CrankPinRadius, eng->WristPinRadius);
  1170.    glEndList();
  1171.  
  1172.    eng->PistonList = glGenLists(1);
  1173.    glNewList(eng->PistonList, GL_COMPILE);
  1174.    DrawPiston(eng);
  1175.    glEndList();
  1176.  
  1177.    eng->BlockList = glGenLists(1);
  1178.    glNewList(eng->BlockList, GL_COMPILE);
  1179.    DrawEngineBlock(eng);
  1180.    glEndList();
  1181. }
  1182.  
  1183.  
  1184. /**
  1185.  * Free engine display lists (render with immediate mode).
  1186.  */
  1187. static void
  1188. FreeDisplayLists(Engine *eng)
  1189. {
  1190.    glDeleteLists(eng->CrankList, 1);
  1191.    eng->CrankList = 0;
  1192.    glDeleteLists(eng->ConnRodList, 1);
  1193.    eng->ConnRodList = 0;
  1194.    glDeleteLists(eng->PistonList, 1);
  1195.    eng->PistonList = 0;
  1196.    glDeleteLists(eng->BlockList, 1);
  1197.    eng->BlockList = 0;
  1198. }
  1199.  
  1200.  
  1201. /**
  1202.  * Draw complete engine.
  1203.  * \param eng  description of engine to draw
  1204.  * \param crankAngle  current crankshaft angle, in radians
  1205.  */
  1206. static void
  1207. DrawEngine(const Engine *eng, float crankAngle)
  1208. {
  1209.    const float crankDelta = 360.0 / eng->Cranks;
  1210.    const float crankLen = CrankshaftLength(eng);
  1211.    const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  1212.    int i;
  1213.  
  1214.    glPushMatrix();
  1215.    glRotatef(eng->V_Angle * 0.5, 0, 0, 1);
  1216.    glTranslatef(0, 0, -0.5 * crankLen);
  1217.  
  1218.    /* crankshaft */
  1219.    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, CrankshaftColor);
  1220.    glColor4fv(CrankshaftColor);
  1221.    DrawPositionedCrankshaft(eng, crankAngle);
  1222.  
  1223.    for (i = 0; i < eng->Pistons; i++) {
  1224.       const float z = PistonShaftPosition(eng, i);
  1225.       const int crank = i / pistonsPerCrank;
  1226.       float rot = crankAngle + crank * crankDelta;
  1227.       int k;
  1228.  
  1229.       glPushMatrix();
  1230.          glTranslatef(0, 0, z);
  1231.  
  1232.          /* additional rotation for kth piston per crank */
  1233.          k = i % pistonsPerCrank;
  1234.          glRotatef(k * -eng->V_Angle, 0, 0, 1);
  1235.          rot += k * eng->V_Angle;
  1236.  
  1237.          /* piston */
  1238.          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, PistonColor);
  1239.          glColor4fv(PistonColor);
  1240.          DrawPositionedPiston(eng, rot);
  1241.  
  1242.          /* connecting rod */
  1243.          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ConnRodColor);
  1244.          glColor4fv(ConnRodColor);
  1245.          DrawPositionedConnectingRod(eng, rot);
  1246.       glPopMatrix();
  1247.    }
  1248.  
  1249.    if (Render.ShowBlock) {
  1250.       const GLboolean blend = glIsEnabled(GL_BLEND);
  1251.  
  1252.       glDepthMask(GL_FALSE);
  1253.       if (!blend) {
  1254.          glEnable(GL_BLEND);
  1255.       }
  1256.       glEnable(GL_CULL_FACE);
  1257.  
  1258.       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, BlockColor);
  1259.       glColor4fv(BlockColor);
  1260.       if (eng->CrankList)
  1261.          glCallList(eng->BlockList);
  1262.       else
  1263.          DrawEngineBlock(eng);
  1264.  
  1265.       glDisable(GL_CULL_FACE);
  1266.       glDepthMask(GL_TRUE);
  1267.       if (!blend) {
  1268.          glDisable(GL_BLEND);
  1269.       }
  1270.    }
  1271.  
  1272.    glPopMatrix();
  1273. }
  1274.  
  1275.  
  1276. static void
  1277. DrawBox(void)
  1278. {
  1279.    const float xmin = -3.0, xmax = 3.0;
  1280.    const float ymin = -1.0, ymax = 3.0;
  1281.    const float zmin = -4.0, zmax = 4.0;
  1282.    const float step = 0.5;
  1283.    const float d = 0.01;
  1284.    float x, y, z;
  1285.    GLboolean lit = glIsEnabled(GL_LIGHTING);
  1286.    GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
  1287.  
  1288.    glDisable(GL_LIGHTING);
  1289.    glDisable(GL_TEXTURE_2D);
  1290.    glLineWidth(1.0);
  1291.  
  1292.    glColor3f(1, 1, 1);
  1293.  
  1294.    /* Z min */
  1295.    glBegin(GL_LINES);
  1296.    for (x = xmin; x <= xmax; x += step) {
  1297.       glVertex3f(x, ymin, zmin);
  1298.       glVertex3f(x, ymax, zmin);
  1299.    }
  1300.    glEnd();
  1301.    glBegin(GL_LINES);
  1302.    for (y = ymin; y <= ymax; y += step) {
  1303.       glVertex3f(xmin, y, zmin);
  1304.       glVertex3f(xmax, y, zmin);
  1305.    }
  1306.    glEnd();
  1307.  
  1308.    /* Y min */
  1309.    glBegin(GL_LINES);
  1310.    for (x = xmin; x <= xmax; x += step) {
  1311.       glVertex3f(x, ymin, zmin);
  1312.       glVertex3f(x, ymin, zmax);
  1313.    }
  1314.    glEnd();
  1315.    glBegin(GL_LINES);
  1316.    for (z = zmin; z <= zmax; z += step) {
  1317.       glVertex3f(xmin, ymin, z);
  1318.       glVertex3f(xmax, ymin, z);
  1319.    }
  1320.    glEnd();
  1321.  
  1322.    /* X min */
  1323.    glBegin(GL_LINES);
  1324.    for (y = ymin; y <= ymax; y += step) {
  1325.       glVertex3f(xmin, y, zmin);
  1326.       glVertex3f(xmin, y, zmax);
  1327.    }
  1328.    glEnd();
  1329.    glBegin(GL_LINES);
  1330.    for (z = zmin; z <= zmax; z += step) {
  1331.       glVertex3f(xmin, ymin, z);
  1332.       glVertex3f(xmin, ymax, z);
  1333.    }
  1334.    glEnd();
  1335.  
  1336.    glColor3f(0.4, 0.4, 0.6);
  1337.    glBegin(GL_QUADS);
  1338.    /* xmin */
  1339.    glVertex3f(xmin-d, ymin, zmin);
  1340.    glVertex3f(xmin-d, ymax, zmin);
  1341.    glVertex3f(xmin-d, ymax, zmax);
  1342.    glVertex3f(xmin-d, ymin, zmax);
  1343.    /* ymin */
  1344.    glVertex3f(xmin, ymin-d, zmin);
  1345.    glVertex3f(xmax, ymin-d, zmin);
  1346.    glVertex3f(xmax, ymin-d, zmax);
  1347.    glVertex3f(xmin, ymin-d, zmax);
  1348.    /* zmin */
  1349.    glVertex3f(xmin, ymin, zmin-d);
  1350.    glVertex3f(xmax, ymin, zmin-d);
  1351.    glVertex3f(xmax, ymax, zmin-d);
  1352.    glVertex3f(xmin, ymax, zmin-d);
  1353.    glEnd();
  1354.  
  1355.    if (lit)
  1356.       glEnable(GL_LIGHTING);
  1357.    if (tex)
  1358.       glEnable(GL_TEXTURE_2D);
  1359. }
  1360.  
  1361. /*
  1362. static void
  1363. PrintString(const char *s)
  1364. {
  1365.    while (*s) {
  1366.       glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
  1367.       s++;
  1368.    }
  1369. }
  1370. */
  1371.  
  1372.  
  1373. void draw(void)
  1374. {
  1375.    int fps;
  1376.    GLfloat rot[4][4];
  1377.  
  1378.    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1379.  
  1380.    glPushMatrix();
  1381.  
  1382.       glTranslatef(0.0, 0.0, -View.Distance);
  1383.       build_rotmatrix(rot, View.CurQuat);
  1384.       glMultMatrixf(&rot[0][0]);
  1385.  
  1386.       glPushMatrix();
  1387.          glTranslatef(0, -0.75, 0);
  1388.          if (Render.DrawBox)
  1389.             DrawBox();
  1390.          DrawEngine(Engines + CurEngine, Theta);
  1391.       glPopMatrix();
  1392.  
  1393.    glPopMatrix();
  1394.  
  1395. }
  1396.  
  1397.  
  1398. /**
  1399.  * Handle window resize.
  1400.  */
  1401. void reshape(int width, int height)
  1402. {
  1403.    float ar = (float) width / height;
  1404.    float s = 0.5;
  1405.    glViewport(0, 0, width, height);
  1406.    glMatrixMode(GL_PROJECTION);
  1407.    glLoadIdentity();
  1408.    glFrustum(-ar * s, ar * s, -s, s, 2.0, 50.0);
  1409.    glMatrixMode(GL_MODELVIEW);
  1410.    glLoadIdentity();
  1411.    WinWidth = width;
  1412.    WinHeight = height;
  1413. }
  1414.  
  1415. #if 0
  1416. /**
  1417.  * Handle mouse button.
  1418.  */
  1419. static void
  1420. Mouse(int button, int state, int x, int y)
  1421. {
  1422.    if (button == GLUT_LEFT_BUTTON) {
  1423.       if (state == GLUT_DOWN) {
  1424.          View.StartX = x;
  1425.          View.StartY = y;
  1426.          View.Rotating = GL_TRUE;
  1427.       }
  1428.       else if (state == GLUT_UP) {
  1429.          View.Rotating = GL_FALSE;
  1430.       }
  1431.    }
  1432.    else if (button == GLUT_MIDDLE_BUTTON) {
  1433.       if (state == GLUT_DOWN) {
  1434.          View.StartX = x;
  1435.          View.StartY = y;
  1436.          View.StartDistance = View.Distance;
  1437.          View.Translating = GL_TRUE;
  1438.       }
  1439.       else if (state == GLUT_UP) {
  1440.          View.Translating = GL_FALSE;
  1441.       }
  1442.    }
  1443. }
  1444.  
  1445.  
  1446. /**
  1447.  * Handle mouse motion
  1448.  */
  1449. static void
  1450. Motion(int x, int y)
  1451. {
  1452.    int i;
  1453.    if (View.Rotating) {
  1454.       float x0 = (2.0 * View.StartX - WinWidth) / WinWidth;
  1455.       float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight;
  1456.       float x1 = (2.0 * x - WinWidth) / WinWidth;
  1457.       float y1 = (WinHeight - 2.0 * y) / WinHeight;
  1458.       float q[4];
  1459.  
  1460.       trackball(q, x0, y0, x1, y1);
  1461.       View.StartX = x;
  1462.       View.StartY = y;
  1463.       for (i = 0; i < 1; i++)
  1464.          add_quats(q, View.CurQuat, View.CurQuat);
  1465.    }
  1466.    else if (View.Translating) {
  1467.       float dz = 0.01 * (y - View.StartY);
  1468.       View.Distance = View.StartDistance + dz;
  1469.    }
  1470. }
  1471. #endif
  1472.  
  1473. /**
  1474.  ** Menu Callbacks
  1475.  **/
  1476.  
  1477. static void
  1478. OptChangeEngine(void)
  1479. {
  1480.    CurEngine = (CurEngine + 1) % NUM_ENGINES;
  1481. }
  1482.  
  1483. static void
  1484. OptRenderMode(void)
  1485. {
  1486.    Render.Mode++;
  1487.    if (Render.Mode > TEXTURED)
  1488.       Render.Mode = 0;
  1489.    SetRenderState(Render.Mode);
  1490. }
  1491.  
  1492. static void
  1493. OptDisplayLists(void)
  1494. {
  1495.    int i;
  1496.    Render.UseLists = !Render.UseLists;
  1497.    if (Render.UseLists) {
  1498.       for (i = 0; i < NUM_ENGINES; i++) {
  1499.          GenerateDisplayLists(Engines + i);
  1500.       }
  1501.    }
  1502.    else {
  1503.       for (i = 0; i < NUM_ENGINES; i++) {
  1504.          FreeDisplayLists(Engines + i);
  1505.       }
  1506.    }
  1507. }
  1508.  
  1509. static void
  1510. OptShowBlock(void)
  1511. {
  1512.    Render.ShowBlock = !Render.ShowBlock;
  1513. }
  1514.  
  1515. static void
  1516. OptShowInfo(void)
  1517. {
  1518.    Render.ShowInfo = !Render.ShowInfo;
  1519. }
  1520.  
  1521. static void
  1522. OptShowBox(void)
  1523. {
  1524.    Render.DrawBox = !Render.DrawBox;
  1525. }
  1526.  
  1527. static void
  1528. OptRotate(void)
  1529. {
  1530.    Theta += 5.0;
  1531. }
  1532.  
  1533. /**
  1534.  * Define menu entries (w/ keyboard shortcuts)
  1535.  */
  1536.  
  1537. typedef struct
  1538. {
  1539.    const char *Text;
  1540.    const char Key;
  1541.    void (*Function)(void);
  1542. } MenuInfo;
  1543.  
  1544. static const MenuInfo MenuItems[] = {
  1545.    { "Change Engine", 'e', OptChangeEngine },
  1546.    { "Rendering Style", 'm', OptRenderMode },
  1547.    { "Display Lists", 'd', OptDisplayLists },
  1548.    { "Show Block", 98, OptShowBlock },    /* b  */
  1549.     { "Show Box", 'x', OptShowBox },
  1550.    { NULL, 'r', OptRotate },
  1551.    { NULL, 0, NULL }
  1552. };
  1553.  
  1554.  
  1555. /**
  1556.  * Handle keyboard event.
  1557.  */
  1558. void Key(unsigned char key, int x, int y)
  1559. {
  1560.    int i;
  1561.    (void) x; (void) y;
  1562.  
  1563.    for (i = 0; MenuItems[i].Key; i++)
  1564.    {
  1565.       if (MenuItems[i].Key == key)
  1566.       {
  1567.          MenuItems[i].Function();
  1568.          break;
  1569.       }
  1570.    }
  1571. }
  1572.  
  1573. static void LoadTexture(void)
  1574. {
  1575.    GLboolean convolve = GL_FALSE;
  1576.  
  1577.    glGenTextures(1, &TextureObj);
  1578.    glBindTexture(GL_TEXTURE_2D, TextureObj);
  1579.    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1580.    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1581.    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  1582.    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  1583.  
  1584.    if (convolve) {
  1585. #define FILTER_SIZE 7
  1586.       /* use convolution to blur the texture to simulate a dull finish
  1587.        * on the object.
  1588.        */
  1589.       GLubyte *img;
  1590.       GLenum format;
  1591.       GLint w, h;
  1592.       GLfloat filter[FILTER_SIZE][FILTER_SIZE][4];
  1593.  
  1594.       for (h = 0; h < FILTER_SIZE; h++) {
  1595.          for (w = 0; w < FILTER_SIZE; w++) {
  1596.             const GLfloat k = 1.0 / (FILTER_SIZE * FILTER_SIZE);
  1597.             filter[h][w][0] = k;
  1598.             filter[h][w][1] = k;
  1599.             filter[h][w][2] = k;
  1600.             filter[h][w][3] = k;
  1601.          }
  1602.       }
  1603.  
  1604.       glEnable(GL_CONVOLUTION_2D);
  1605.       glConvolutionParameteri(GL_CONVOLUTION_2D,
  1606.                               GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER);
  1607.       glConvolutionFilter2D(GL_CONVOLUTION_2D, GL_RGBA,
  1608.                             FILTER_SIZE, FILTER_SIZE,
  1609.                             GL_RGBA, GL_FLOAT, filter);
  1610.  
  1611.       img = LoadRGBImage(TEXTURE_FILE, &w, &h, &format);
  1612.       if (!img) {
  1613.          printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
  1614.          exit(1);
  1615.       }
  1616.  
  1617.       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
  1618.                    format, GL_UNSIGNED_BYTE, img);
  1619.       free(img);
  1620.    }
  1621.    else {
  1622.       if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
  1623.          printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
  1624.          exit(1);
  1625.       }
  1626.    }
  1627. }
  1628.  
  1629.  
  1630. void init(void)
  1631. {
  1632.    const GLfloat lightColor[4] = { 0.7, 0.7, 0.7, 1.0 };
  1633.    const GLfloat specular[4] = { 0.8, 0.8, 0.8, 1.0 };
  1634.    const GLfloat backColor[4] = { 1, 1, 0, 0 };
  1635.  
  1636.    Q = gluNewQuadric();
  1637.    gluQuadricNormals(Q, GLU_SMOOTH);
  1638.  
  1639.    LoadTexture();
  1640.  
  1641.    glClearColor(0.3, 0.3, 0.3, 0.0);
  1642.    glEnable(GL_DEPTH_TEST);
  1643.    glEnable(GL_LIGHTING);
  1644.    glEnable(GL_LIGHT0);
  1645.    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
  1646.    glMaterialf(GL_FRONT, GL_SHININESS, 40);
  1647.    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
  1648.    glEnable(GL_NORMALIZE);
  1649.  
  1650.    glMaterialfv(GL_BACK, GL_DIFFUSE, backColor);
  1651. #if 0
  1652.    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
  1653. #endif
  1654.    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1655.  
  1656.    InitViewInfo(&View);
  1657.    InitRenderInfo(&Render);
  1658. }
  1659.  
  1660. int atexit(void (*func)(void))
  1661. {
  1662.     return 0;
  1663. };
  1664.  
  1665. /*
  1666. #define GL_NO_ERROR                             0x0
  1667. #define GL_INVALID_ENUM                         0x0500
  1668. #define GL_INVALID_VALUE                        0x0501
  1669. #define GL_INVALID_OPERATION                    0x0502
  1670. #define GL_STACK_OVERFLOW                       0x0503
  1671. #define GL_STACK_UNDERFLOW                      0x0504
  1672. #define GL_OUT_OF_MEMORY                        0x0505
  1673. */
  1674.  
  1675.  
  1676.  
  1677.