engine.c revision 32001f49
132001f49Smrg/** 232001f49Smrg * Simple engine demo (crankshaft, pistons, connecting rods) 332001f49Smrg * 432001f49Smrg * Brian Paul 532001f49Smrg * June 2006 632001f49Smrg */ 732001f49Smrg 832001f49Smrg#include <assert.h> 932001f49Smrg#include <stdio.h> 1032001f49Smrg#include <stdlib.h> 1132001f49Smrg#include <math.h> 1232001f49Smrg#include <GL/glew.h> 1332001f49Smrg#include "glut_wrap.h" 1432001f49Smrg#include "readtex.h" 1532001f49Smrg#include "trackball.h" 1632001f49Smrg 1732001f49Smrg 1832001f49Smrg#ifndef M_PI 1932001f49Smrg#define M_PI 3.14159265358979323846 2032001f49Smrg#endif 2132001f49Smrg 2232001f49Smrg#define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.0) 2332001f49Smrg 2432001f49Smrg#define TEXTURE_FILE DEMOS_DATA_DIR "reflect.rgb" 2532001f49Smrg 2632001f49Smrg/* Target engine speed: */ 2732001f49Smrgconst int RPM = 100.0; 2832001f49Smrg 2932001f49Smrgstatic int Win = 0; 3032001f49Smrg 3132001f49Smrg 3232001f49Smrg/** 3332001f49Smrg * Engine description. 3432001f49Smrg */ 3532001f49Smrgtypedef struct 3632001f49Smrg{ 3732001f49Smrg const char *Name; 3832001f49Smrg int Pistons; 3932001f49Smrg int Cranks; 4032001f49Smrg float V_Angle; 4132001f49Smrg float PistonRadius; 4232001f49Smrg float PistonHeight; 4332001f49Smrg float WristPinRadius; 4432001f49Smrg float Throw; 4532001f49Smrg float CrankPlateThickness; 4632001f49Smrg float CrankPinRadius; 4732001f49Smrg float CrankJournalRadius; 4832001f49Smrg float CrankJournalLength; 4932001f49Smrg float ConnectingRodLength; 5032001f49Smrg float ConnectingRodThickness; 5132001f49Smrg /* display list IDs */ 5232001f49Smrg GLuint CrankList; 5332001f49Smrg GLuint ConnRodList; 5432001f49Smrg GLuint PistonList; 5532001f49Smrg GLuint BlockList; 5632001f49Smrg} Engine; 5732001f49Smrg 5832001f49Smrg 5932001f49Smrgtypedef struct 6032001f49Smrg{ 6132001f49Smrg float CurQuat[4]; 6232001f49Smrg float Distance; 6332001f49Smrg /* When mouse is moving: */ 6432001f49Smrg GLboolean Rotating, Translating; 6532001f49Smrg GLint StartX, StartY; 6632001f49Smrg float StartDistance; 6732001f49Smrg} ViewInfo; 6832001f49Smrg 6932001f49Smrg 7032001f49Smrgtypedef enum 7132001f49Smrg{ 7232001f49Smrg LIT, 7332001f49Smrg WIREFRAME, 7432001f49Smrg TEXTURED 7532001f49Smrg} RenderMode; 7632001f49Smrg 7732001f49Smrg 7832001f49Smrgtypedef struct 7932001f49Smrg{ 8032001f49Smrg RenderMode Mode; 8132001f49Smrg GLboolean Anim; 8232001f49Smrg GLboolean Wireframe; 8332001f49Smrg GLboolean Blend; 8432001f49Smrg GLboolean Antialias; 8532001f49Smrg GLboolean Texture; 8632001f49Smrg GLboolean UseLists; 8732001f49Smrg GLboolean DrawBox; 8832001f49Smrg GLboolean ShowInfo; 8932001f49Smrg GLboolean ShowBlock; 9032001f49Smrg} RenderInfo; 9132001f49Smrg 9232001f49Smrg 9332001f49Smrgstatic GLUquadric *Q; 9432001f49Smrg 9532001f49Smrgstatic GLfloat Theta = 0.0; 9632001f49Smrg 9732001f49Smrgstatic const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 }; 9832001f49Smrgstatic const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 }; 9932001f49Smrgstatic const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 }; 10032001f49Smrgstatic const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 }; 10132001f49Smrg 10232001f49Smrgstatic GLuint TextureObj; 10332001f49Smrgstatic GLint WinWidth = 800, WinHeight = 500; 10432001f49Smrg 10532001f49Smrgstatic ViewInfo View; 10632001f49Smrgstatic RenderInfo Render; 10732001f49Smrg 10832001f49Smrg#define NUM_ENGINES 3 10932001f49Smrgstatic Engine Engines[NUM_ENGINES] = 11032001f49Smrg{ 11132001f49Smrg { 11232001f49Smrg "V-6", 11332001f49Smrg 6, /* Pistons */ 11432001f49Smrg 3, /* Cranks */ 11532001f49Smrg 90.0, /* V_Angle */ 11632001f49Smrg 0.5, /* PistonRadius */ 11732001f49Smrg 0.6, /* PistonHeight */ 11832001f49Smrg 0.1, /* WristPinRadius */ 11932001f49Smrg 0.5, /* Throw */ 12032001f49Smrg 0.2, /* CrankPlateThickness */ 12132001f49Smrg 0.25, /* CrankPinRadius */ 12232001f49Smrg 0.3, /* CrankJournalRadius */ 12332001f49Smrg 0.4, /* CrankJournalLength */ 12432001f49Smrg 1.5, /* ConnectingRodLength */ 12532001f49Smrg 0.1, /* ConnectingRodThickness */ 12632001f49Smrg 0, /* CrankList */ 12732001f49Smrg 0, /* ConnRodList */ 12832001f49Smrg 0, /* PistonList */ 12932001f49Smrg 0 /* BlockList */ 13032001f49Smrg }, 13132001f49Smrg { 13232001f49Smrg "Inline-4", 13332001f49Smrg 4, /* Pistons */ 13432001f49Smrg 4, /* Cranks */ 13532001f49Smrg 0.0, /* V_Angle */ 13632001f49Smrg 0.5, /* PistonRadius */ 13732001f49Smrg 0.6, /* PistonHeight */ 13832001f49Smrg 0.1, /* WristPinRadius */ 13932001f49Smrg 0.5, /* Throw */ 14032001f49Smrg 0.2, /* CrankPlateThickness */ 14132001f49Smrg 0.25, /* CrankPinRadius */ 14232001f49Smrg 0.3, /* CrankJournalRadius */ 14332001f49Smrg 0.4, /* CrankJournalLength */ 14432001f49Smrg 1.5, /* ConnectingRodLength */ 14532001f49Smrg 0.1, /* ConnectingRodThickness */ 14632001f49Smrg 0, /* CrankList */ 14732001f49Smrg 0, /* ConnRodList */ 14832001f49Smrg 0, /* PistonList */ 14932001f49Smrg 0 /* BlockList */ 15032001f49Smrg }, 15132001f49Smrg { 15232001f49Smrg "Boxer-6", 15332001f49Smrg 6, /* Pistons */ 15432001f49Smrg 3, /* Cranks */ 15532001f49Smrg 180.0,/* V_Angle */ 15632001f49Smrg 0.5, /* PistonRadius */ 15732001f49Smrg 0.6, /* PistonHeight */ 15832001f49Smrg 0.1, /* WristPinRadius */ 15932001f49Smrg 0.5, /* Throw */ 16032001f49Smrg 0.2, /* CrankPlateThickness */ 16132001f49Smrg 0.25, /* CrankPinRadius */ 16232001f49Smrg 0.3, /* CrankJournalRadius */ 16332001f49Smrg 0.4, /* CrankJournalLength */ 16432001f49Smrg 1.5, /* ConnectingRodLength */ 16532001f49Smrg 0.1, /* ConnectingRodThickness */ 16632001f49Smrg 0, /* CrankList */ 16732001f49Smrg 0, /* ConnRodList */ 16832001f49Smrg 0, /* PistonList */ 16932001f49Smrg 0 /* BlockList */ 17032001f49Smrg } 17132001f49Smrg}; 17232001f49Smrg 17332001f49Smrgstatic int CurEngine = 0; 17432001f49Smrg 17532001f49Smrg 17632001f49Smrg 17732001f49Smrgstatic void 17832001f49SmrgInitViewInfo(ViewInfo *view) 17932001f49Smrg{ 18032001f49Smrg view->Rotating = GL_FALSE; 18132001f49Smrg view->Translating = GL_FALSE; 18232001f49Smrg view->StartX = view->StartY = 0; 18332001f49Smrg view->Distance = 12.0; 18432001f49Smrg view->StartDistance = 0.0; 18532001f49Smrg view->CurQuat[0] = -0.194143; 18632001f49Smrg view->CurQuat[1] = 0.507848; 18732001f49Smrg view->CurQuat[2] = 0.115245; 18832001f49Smrg view->CurQuat[3] = 0.831335; 18932001f49Smrg} 19032001f49Smrg 19132001f49Smrg 19232001f49Smrgstatic void 19332001f49SmrgInitRenderInfo(RenderInfo *render) 19432001f49Smrg{ 19532001f49Smrg render->Mode = LIT; 19632001f49Smrg render->Anim = GL_TRUE; 19732001f49Smrg render->Wireframe = GL_FALSE; 19832001f49Smrg render->Blend = GL_FALSE; 19932001f49Smrg render->Antialias = GL_FALSE; 20032001f49Smrg render->Texture = GL_FALSE; 20132001f49Smrg render->DrawBox = GL_FALSE; 20232001f49Smrg render->ShowInfo = GL_TRUE; 20332001f49Smrg render->ShowBlock = GL_FALSE; 20432001f49Smrg render->UseLists = GL_FALSE; 20532001f49Smrg} 20632001f49Smrg 20732001f49Smrg 20832001f49Smrg/** 20932001f49Smrg * Set GL for given rendering mode. 21032001f49Smrg */ 21132001f49Smrgstatic void 21232001f49SmrgSetRenderState(RenderMode mode) 21332001f49Smrg{ 21432001f49Smrg static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 }; 21532001f49Smrg static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 }; 21632001f49Smrg 21732001f49Smrg /* defaults */ 21832001f49Smrg glDisable(GL_LIGHTING); 21932001f49Smrg glDisable(GL_TEXTURE_2D); 22032001f49Smrg glDisable(GL_BLEND); 22132001f49Smrg glDisable(GL_LINE_SMOOTH); 22232001f49Smrg glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 22332001f49Smrg glDisable(GL_TEXTURE_GEN_S); 22432001f49Smrg glDisable(GL_TEXTURE_GEN_T); 22532001f49Smrg glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2); 22632001f49Smrg 22732001f49Smrg switch (mode) { 22832001f49Smrg case LIT: 22932001f49Smrg glEnable(GL_LIGHTING); 23032001f49Smrg break; 23132001f49Smrg case WIREFRAME: 23232001f49Smrg glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 23332001f49Smrg glEnable(GL_LINE_SMOOTH); 23432001f49Smrg glEnable(GL_BLEND); 23532001f49Smrg glLineWidth(1.5); 23632001f49Smrg break; 23732001f49Smrg case TEXTURED: 23832001f49Smrg glEnable(GL_LIGHTING); 23932001f49Smrg glEnable(GL_TEXTURE_2D); 24032001f49Smrg glEnable(GL_TEXTURE_GEN_S); 24132001f49Smrg glEnable(GL_TEXTURE_GEN_T); 24232001f49Smrg glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4); 24332001f49Smrg break; 24432001f49Smrg default: 24532001f49Smrg ; 24632001f49Smrg } 24732001f49Smrg} 24832001f49Smrg 24932001f49Smrg 25032001f49Smrg/** 25132001f49Smrg * Animate the engine parts. 25232001f49Smrg */ 25332001f49Smrgstatic void 25432001f49SmrgIdle(void) 25532001f49Smrg{ 25632001f49Smrg /* convert degrees per millisecond to RPM: */ 25732001f49Smrg const float m = 360.0 / 1000.0 / 60.0; 25832001f49Smrg GLint t = glutGet(GLUT_ELAPSED_TIME); 25932001f49Smrg Theta = ((int) (t * RPM * m)) % 360; 26032001f49Smrg glutPostRedisplay(); 26132001f49Smrg} 26232001f49Smrg 26332001f49Smrg 26432001f49Smrg/** 26532001f49Smrg * Compute piston's position along its stroke. 26632001f49Smrg */ 26732001f49Smrgstatic float 26832001f49SmrgPistonStrokePosition(float throwDist, float crankAngle, float connRodLength) 26932001f49Smrg{ 27032001f49Smrg float x = throwDist * cos(DEG_TO_RAD(crankAngle)); 27132001f49Smrg float y = throwDist * sin(DEG_TO_RAD(crankAngle)); 27232001f49Smrg float pos = y + sqrt(connRodLength * connRodLength - x * x); 27332001f49Smrg return pos; 27432001f49Smrg} 27532001f49Smrg 27632001f49Smrg 27732001f49Smrg/** 27832001f49Smrg * Compute position of nth piston along the crankshaft. 27932001f49Smrg */ 28032001f49Smrgstatic float 28132001f49SmrgPistonShaftPosition(const Engine *eng, int piston) 28232001f49Smrg{ 28332001f49Smrg const int i = piston / (eng->Pistons / eng->Cranks); 28432001f49Smrg float z; 28532001f49Smrg assert(piston < eng->Pistons); 28632001f49Smrg z = 1.5 * eng->CrankJournalLength + eng->CrankPlateThickness 28732001f49Smrg + i * (2.0 * (eng->CrankJournalLength + eng->CrankPlateThickness)); 28832001f49Smrg if (eng->Pistons > eng->Cranks) { 28932001f49Smrg if (piston & 1) 29032001f49Smrg z += eng->ConnectingRodThickness; 29132001f49Smrg else 29232001f49Smrg z -= eng->ConnectingRodThickness; 29332001f49Smrg } 29432001f49Smrg return z; 29532001f49Smrg} 29632001f49Smrg 29732001f49Smrg 29832001f49Smrg/** 29932001f49Smrg * Compute distance between two adjacent pistons 30032001f49Smrg */ 30132001f49Smrgstatic float 30232001f49SmrgPistonSpacing(const Engine *eng) 30332001f49Smrg{ 30432001f49Smrg const int pistonsPerCrank = eng->Pistons / eng->Cranks; 30532001f49Smrg const float z0 = PistonShaftPosition(eng, 0); 30632001f49Smrg const float z1 = PistonShaftPosition(eng, pistonsPerCrank); 30732001f49Smrg return z1 - z0; 30832001f49Smrg} 30932001f49Smrg 31032001f49Smrg 31132001f49Smrg/** 31232001f49Smrg * (x0, y0) = position of big end on crankshaft 31332001f49Smrg * (x1, y1) = position of small end on piston 31432001f49Smrg */ 31532001f49Smrgstatic void 31632001f49SmrgComputeConnectingRodPosition(float throwDist, float crankAngle, 31732001f49Smrg float connRodLength, 31832001f49Smrg float *x0, float *y0, float *x1, float *y1) 31932001f49Smrg{ 32032001f49Smrg *x0 = throwDist * cos(DEG_TO_RAD(crankAngle)); 32132001f49Smrg *y0 = throwDist * sin(DEG_TO_RAD(crankAngle)); 32232001f49Smrg *x1 = 0.0; 32332001f49Smrg *y1 = PistonStrokePosition(throwDist, crankAngle, connRodLength); 32432001f49Smrg} 32532001f49Smrg 32632001f49Smrg 32732001f49Smrg/** 32832001f49Smrg * Compute total length of the crankshaft. 32932001f49Smrg */ 33032001f49Smrgstatic float 33132001f49SmrgCrankshaftLength(const Engine *eng) 33232001f49Smrg{ 33332001f49Smrg float len = (eng->Cranks * 2 + 1) * eng->CrankJournalLength 33432001f49Smrg + 2 * eng->Cranks * eng->CrankPlateThickness; 33532001f49Smrg return len; 33632001f49Smrg} 33732001f49Smrg 33832001f49Smrg 33932001f49Smrg/** 34032001f49Smrg * Draw a piston. 34132001f49Smrg * Axis of piston = Z axis. Wrist pin is centered on (0, 0, 0). 34232001f49Smrg */ 34332001f49Smrgstatic void 34432001f49SmrgDrawPiston(const Engine *eng) 34532001f49Smrg{ 34632001f49Smrg const int slices = 30, stacks = 4, loops = 4; 34732001f49Smrg const float innerRadius = 0.9 * eng->PistonRadius; 34832001f49Smrg const float innerHeight = eng->PistonHeight - 0.15; 34932001f49Smrg const float wristPinLength = 1.8 * eng->PistonRadius; 35032001f49Smrg 35132001f49Smrg assert(Q); 35232001f49Smrg 35332001f49Smrg glPushMatrix(); 35432001f49Smrg glTranslatef(0, 0, -1.1 * eng->WristPinRadius); 35532001f49Smrg 35632001f49Smrg gluQuadricOrientation(Q, GLU_INSIDE); 35732001f49Smrg 35832001f49Smrg /* bottom rim */ 35932001f49Smrg gluDisk(Q, innerRadius, eng->PistonRadius, slices, 1/*loops*/); 36032001f49Smrg 36132001f49Smrg /* inner cylinder */ 36232001f49Smrg gluCylinder(Q, innerRadius, innerRadius, innerHeight, slices, stacks); 36332001f49Smrg 36432001f49Smrg /* inside top */ 36532001f49Smrg glPushMatrix(); 36632001f49Smrg glTranslatef(0, 0, innerHeight); 36732001f49Smrg gluDisk(Q, 0, innerRadius, slices, loops); 36832001f49Smrg glPopMatrix(); 36932001f49Smrg 37032001f49Smrg gluQuadricOrientation(Q, GLU_OUTSIDE); 37132001f49Smrg 37232001f49Smrg /* outer cylinder */ 37332001f49Smrg gluCylinder(Q, eng->PistonRadius, eng->PistonRadius, eng->PistonHeight, 37432001f49Smrg slices, stacks); 37532001f49Smrg 37632001f49Smrg /* top */ 37732001f49Smrg glTranslatef(0, 0, eng->PistonHeight); 37832001f49Smrg gluDisk(Q, 0, eng->PistonRadius, slices, loops); 37932001f49Smrg 38032001f49Smrg glPopMatrix(); 38132001f49Smrg 38232001f49Smrg /* wrist pin */ 38332001f49Smrg glPushMatrix(); 38432001f49Smrg glTranslatef(0, 0.5 * wristPinLength, 0.0); 38532001f49Smrg glRotatef(90, 1, 0, 0); 38632001f49Smrg gluCylinder(Q, eng->WristPinRadius, eng->WristPinRadius, wristPinLength, 38732001f49Smrg slices, stacks); 38832001f49Smrg glPopMatrix(); 38932001f49Smrg} 39032001f49Smrg 39132001f49Smrg 39232001f49Smrg/** 39332001f49Smrg * Draw piston at particular position. 39432001f49Smrg */ 39532001f49Smrgstatic void 39632001f49SmrgDrawPositionedPiston(const Engine *eng, float crankAngle) 39732001f49Smrg{ 39832001f49Smrg const float pos = PistonStrokePosition(eng->Throw, crankAngle, 39932001f49Smrg eng->ConnectingRodLength); 40032001f49Smrg glPushMatrix(); 40132001f49Smrg glRotatef(-90, 1, 0, 0); 40232001f49Smrg glTranslatef(0, 0, pos); 40332001f49Smrg if (eng->PistonList) 40432001f49Smrg glCallList(eng->PistonList); 40532001f49Smrg else 40632001f49Smrg DrawPiston(eng); 40732001f49Smrg glPopMatrix(); 40832001f49Smrg} 40932001f49Smrg 41032001f49Smrg 41132001f49Smrg/** 41232001f49Smrg * Draw connector plate. Used for crankshaft and connecting rods. 41332001f49Smrg */ 41432001f49Smrgstatic void 41532001f49SmrgDrawConnector(float length, float thickness, 41632001f49Smrg float bigEndRadius, float smallEndRadius) 41732001f49Smrg{ 41832001f49Smrg const float bigRadius = 1.2 * bigEndRadius; 41932001f49Smrg const float smallRadius = 1.2 * smallEndRadius; 42032001f49Smrg const float z0 = -0.5 * thickness, z1 = -z0; 42132001f49Smrg GLfloat points[36][2], normals[36][2]; 42232001f49Smrg int i; 42332001f49Smrg 42432001f49Smrg /* compute vertex locations, normals */ 42532001f49Smrg for (i = 0; i < 36; i++) { 42632001f49Smrg const int angle = i * 10; 42732001f49Smrg float x = cos(DEG_TO_RAD(angle)); 42832001f49Smrg float y = sin(DEG_TO_RAD(angle)); 42932001f49Smrg normals[i][0] = x; 43032001f49Smrg normals[i][1] = y; 43132001f49Smrg if (angle >= 0 && angle <= 180) { 43232001f49Smrg x *= smallRadius; 43332001f49Smrg y = y * smallRadius + length; 43432001f49Smrg } 43532001f49Smrg else { 43632001f49Smrg x *= bigRadius; 43732001f49Smrg y *= bigRadius; 43832001f49Smrg } 43932001f49Smrg points[i][0] = x; 44032001f49Smrg points[i][1] = y; 44132001f49Smrg } 44232001f49Smrg 44332001f49Smrg /* front face */ 44432001f49Smrg glNormal3f(0, 0, 1); 44532001f49Smrg glBegin(GL_POLYGON); 44632001f49Smrg for (i = 0; i < 36; i++) { 44732001f49Smrg glVertex3f(points[i][0], points[i][1], z1); 44832001f49Smrg } 44932001f49Smrg glEnd(); 45032001f49Smrg 45132001f49Smrg /* back face */ 45232001f49Smrg glNormal3f(0, 0, -1); 45332001f49Smrg glBegin(GL_POLYGON); 45432001f49Smrg for (i = 0; i < 36; i++) { 45532001f49Smrg glVertex3f(points[35-i][0], points[35-i][1], z0); 45632001f49Smrg } 45732001f49Smrg glEnd(); 45832001f49Smrg 45932001f49Smrg /* edge */ 46032001f49Smrg glBegin(GL_QUAD_STRIP); 46132001f49Smrg for (i = 0; i <= 36; i++) { 46232001f49Smrg const int j = i % 36; 46332001f49Smrg glNormal3f(normals[j][0], normals[j][1], 0); 46432001f49Smrg glVertex3f(points[j][0], points[j][1], z1); 46532001f49Smrg glVertex3f(points[j][0], points[j][1], z0); 46632001f49Smrg } 46732001f49Smrg glEnd(); 46832001f49Smrg} 46932001f49Smrg 47032001f49Smrg 47132001f49Smrg/** 47232001f49Smrg * Draw a crankshaft. Shaft lies along +Z axis, starting at zero. 47332001f49Smrg */ 47432001f49Smrgstatic void 47532001f49SmrgDrawCrankshaft(const Engine *eng) 47632001f49Smrg{ 47732001f49Smrg const int slices = 20, stacks = 2; 47832001f49Smrg const int n = eng->Cranks * 4 + 1; 47932001f49Smrg const float phiStep = 360 / eng->Cranks; 48032001f49Smrg float phi = -90.0; 48132001f49Smrg int i; 48232001f49Smrg float z = 0.0; 48332001f49Smrg 48432001f49Smrg for (i = 0; i < n; i++) { 48532001f49Smrg glPushMatrix(); 48632001f49Smrg glTranslatef(0, 0, z); 48732001f49Smrg if (i & 1) { 48832001f49Smrg /* draw a crank plate */ 48932001f49Smrg glRotatef(phi, 0, 0, 1); 49032001f49Smrg glTranslatef(0, 0, 0.5 * eng->CrankPlateThickness); 49132001f49Smrg DrawConnector(eng->Throw, eng->CrankPlateThickness, 49232001f49Smrg eng->CrankJournalRadius, eng->CrankPinRadius); 49332001f49Smrg z += 0.2; 49432001f49Smrg if (i % 4 == 3) 49532001f49Smrg phi += phiStep; 49632001f49Smrg } 49732001f49Smrg else if (i % 4 == 0) { 49832001f49Smrg /* draw crank journal segment */ 49932001f49Smrg gluCylinder(Q, eng->CrankJournalRadius, eng->CrankJournalRadius, 50032001f49Smrg eng->CrankJournalLength, slices, stacks); 50132001f49Smrg z += eng->CrankJournalLength; 50232001f49Smrg } 50332001f49Smrg else if (i % 4 == 2) { 50432001f49Smrg /* draw crank pin segment */ 50532001f49Smrg glRotatef(phi, 0, 0, 1); 50632001f49Smrg glTranslatef(0, eng->Throw, 0); 50732001f49Smrg gluCylinder(Q, eng->CrankPinRadius, eng->CrankPinRadius, 50832001f49Smrg eng->CrankJournalLength, slices, stacks); 50932001f49Smrg z += eng->CrankJournalLength; 51032001f49Smrg } 51132001f49Smrg glPopMatrix(); 51232001f49Smrg } 51332001f49Smrg} 51432001f49Smrg 51532001f49Smrg 51632001f49Smrg/** 51732001f49Smrg * Draw crankshaft at a particular rotation. 51832001f49Smrg * \param crankAngle current crankshaft rotation, in radians 51932001f49Smrg */ 52032001f49Smrgstatic void 52132001f49SmrgDrawPositionedCrankshaft(const Engine *eng, float crankAngle) 52232001f49Smrg{ 52332001f49Smrg glPushMatrix(); 52432001f49Smrg glRotatef(crankAngle, 0, 0, 1); 52532001f49Smrg if (eng->CrankList) 52632001f49Smrg glCallList(eng->CrankList); 52732001f49Smrg else 52832001f49Smrg DrawCrankshaft(eng); 52932001f49Smrg glPopMatrix(); 53032001f49Smrg} 53132001f49Smrg 53232001f49Smrg 53332001f49Smrg/** 53432001f49Smrg * Draw a connecting rod at particular position. 53532001f49Smrg * \param eng description of connecting rod to draw 53632001f49Smrg * \param crankAngle current crankshaft rotation, in radians 53732001f49Smrg */ 53832001f49Smrgstatic void 53932001f49SmrgDrawPositionedConnectingRod(const Engine *eng, float crankAngle) 54032001f49Smrg{ 54132001f49Smrg float x0, y0, x1, y1; 54232001f49Smrg float d, phi; 54332001f49Smrg 54432001f49Smrg ComputeConnectingRodPosition(eng->Throw, crankAngle, 54532001f49Smrg eng->ConnectingRodLength, 54632001f49Smrg &x0, &y0, &x1, &y1); 54732001f49Smrg d = sqrt(eng->ConnectingRodLength * eng->ConnectingRodLength - x0 * x0); 54832001f49Smrg phi = atan(x0 / d) * 180.0 / M_PI; 54932001f49Smrg 55032001f49Smrg glPushMatrix(); 55132001f49Smrg glTranslatef(x0, y0, 0); 55232001f49Smrg glRotatef(phi, 0, 0, 1); 55332001f49Smrg if (eng->ConnRodList) 55432001f49Smrg glCallList(eng->ConnRodList); 55532001f49Smrg else 55632001f49Smrg DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness, 55732001f49Smrg eng->CrankPinRadius, eng->WristPinRadius); 55832001f49Smrg glPopMatrix(); 55932001f49Smrg} 56032001f49Smrg 56132001f49Smrg 56232001f49Smrg/** 56332001f49Smrg * Draw a square with a hole in middle. 56432001f49Smrg */ 56532001f49Smrgstatic void 56632001f49SmrgSquareWithHole(float squareSize, float holeRadius) 56732001f49Smrg{ 56832001f49Smrg int i; 56932001f49Smrg glBegin(GL_QUAD_STRIP); 57032001f49Smrg glNormal3f(0, 0, 1); 57132001f49Smrg for (i = 0; i <= 360; i += 5) { 57232001f49Smrg const float x1 = holeRadius * cos(DEG_TO_RAD(i)); 57332001f49Smrg const float y1 = holeRadius * sin(DEG_TO_RAD(i)); 57432001f49Smrg float x2 = 0.0F, y2 = 0.0F; 57532001f49Smrg if (i > 315 || i <= 45) { 57632001f49Smrg x2 = squareSize; 57732001f49Smrg y2 = squareSize * tan(DEG_TO_RAD(i)); 57832001f49Smrg } 57932001f49Smrg else if (i > 45 && i <= 135) { 58032001f49Smrg x2 = -squareSize * tan(DEG_TO_RAD(i - 90)); 58132001f49Smrg y2 = squareSize; 58232001f49Smrg } 58332001f49Smrg else if (i > 135 && i <= 225) { 58432001f49Smrg x2 = -squareSize; 58532001f49Smrg y2 = -squareSize * tan(DEG_TO_RAD(i-180)); 58632001f49Smrg } 58732001f49Smrg else if (i > 225 && i <= 315) { 58832001f49Smrg x2 = squareSize * tan(DEG_TO_RAD(i - 270)); 58932001f49Smrg y2 = -squareSize; 59032001f49Smrg } 59132001f49Smrg glVertex2f(x1, y1); /* inner circle */ 59232001f49Smrg glVertex2f(x2, y2); /* outer square */ 59332001f49Smrg } 59432001f49Smrg glEnd(); 59532001f49Smrg} 59632001f49Smrg 59732001f49Smrg 59832001f49Smrg/** 59932001f49Smrg * Draw block with hole through middle. 60032001f49Smrg * Hole is centered on Z axis. 60132001f49Smrg * Bottom of block is at z=0, top of block is at z = blockHeight. 60232001f49Smrg * index is in [0, count - 1] to determine which block faces are drawn. 60332001f49Smrg */ 60432001f49Smrgstatic void 60532001f49SmrgDrawBlockWithHole(float blockSize, float blockHeight, float holeRadius, 60632001f49Smrg int index, int count) 60732001f49Smrg{ 60832001f49Smrg const int slices = 30, stacks = 4; 60932001f49Smrg const float x = blockSize; 61032001f49Smrg const float y = blockSize; 61132001f49Smrg const float z0 = 0; 61232001f49Smrg const float z1 = blockHeight; 61332001f49Smrg 61432001f49Smrg assert(index < count); 61532001f49Smrg assert(Q); 61632001f49Smrg gluQuadricOrientation(Q, GLU_INSIDE); 61732001f49Smrg 61832001f49Smrg glBegin(GL_QUADS); 61932001f49Smrg /* +X face */ 62032001f49Smrg glNormal3f(1, 0, 0); 62132001f49Smrg glVertex3f( x, -y, z0); 62232001f49Smrg glVertex3f( x, y, z0); 62332001f49Smrg glVertex3f( x, y, z1); 62432001f49Smrg glVertex3f( x, -y, z1); 62532001f49Smrg /* -X face */ 62632001f49Smrg glNormal3f(-1, 0, 0); 62732001f49Smrg glVertex3f(-x, -y, z1); 62832001f49Smrg glVertex3f(-x, y, z1); 62932001f49Smrg glVertex3f(-x, y, z0); 63032001f49Smrg glVertex3f(-x, -y, z0); 63132001f49Smrg if (index == 0) { 63232001f49Smrg /* +Y face */ 63332001f49Smrg glNormal3f(0, 1, 0); 63432001f49Smrg glVertex3f(-x, y, z1); 63532001f49Smrg glVertex3f( x, y, z1); 63632001f49Smrg glVertex3f( x, y, z0); 63732001f49Smrg glVertex3f(-x, y, z0); 63832001f49Smrg } 63932001f49Smrg if (index == count - 1) { 64032001f49Smrg /* -Y face */ 64132001f49Smrg glNormal3f(0, -1, 0); 64232001f49Smrg glVertex3f(-x, -y, z0); 64332001f49Smrg glVertex3f( x, -y, z0); 64432001f49Smrg glVertex3f( x, -y, z1); 64532001f49Smrg glVertex3f(-x, -y, z1); 64632001f49Smrg } 64732001f49Smrg glEnd(); 64832001f49Smrg 64932001f49Smrg /* cylinder / hole */ 65032001f49Smrg gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks); 65132001f49Smrg 65232001f49Smrg /* face at z0 */ 65332001f49Smrg glPushMatrix(); 65432001f49Smrg glRotatef(180, 1, 0, 0); 65532001f49Smrg SquareWithHole(blockSize, holeRadius); 65632001f49Smrg glPopMatrix(); 65732001f49Smrg 65832001f49Smrg /* face at z1 */ 65932001f49Smrg glTranslatef(0, 0, z1); 66032001f49Smrg SquareWithHole(blockSize, holeRadius); 66132001f49Smrg 66232001f49Smrg gluQuadricOrientation(Q, GLU_OUTSIDE); 66332001f49Smrg} 66432001f49Smrg 66532001f49Smrg 66632001f49Smrg/** 66732001f49Smrg * Draw the engine block. 66832001f49Smrg */ 66932001f49Smrgstatic void 67032001f49SmrgDrawEngineBlock(const Engine *eng) 67132001f49Smrg{ 67232001f49Smrg const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight; 67332001f49Smrg const float cylRadius = 1.01 * eng->PistonRadius; 67432001f49Smrg const float blockSize = 0.5 * PistonSpacing(eng); 67532001f49Smrg const int pistonsPerCrank = eng->Pistons / eng->Cranks; 67632001f49Smrg int i; 67732001f49Smrg 67832001f49Smrg for (i = 0; i < eng->Pistons; i++) { 67932001f49Smrg const float z = PistonShaftPosition(eng, i); 68032001f49Smrg const int crank = i / pistonsPerCrank; 68132001f49Smrg int k; 68232001f49Smrg 68332001f49Smrg glPushMatrix(); 68432001f49Smrg glTranslatef(0, 0, z); 68532001f49Smrg 68632001f49Smrg /* additional rotation for kth piston per crank */ 68732001f49Smrg k = i % pistonsPerCrank; 68832001f49Smrg glRotatef(k * -eng->V_Angle, 0, 0, 1); 68932001f49Smrg 69032001f49Smrg /* the block */ 69132001f49Smrg glRotatef(-90, 1, 0, 0); 69232001f49Smrg glTranslatef(0, 0, eng->Throw * 2); 69332001f49Smrg DrawBlockWithHole(blockSize, blockHeight, cylRadius, 69432001f49Smrg crank, eng->Cranks); 69532001f49Smrg glPopMatrix(); 69632001f49Smrg } 69732001f49Smrg} 69832001f49Smrg 69932001f49Smrg 70032001f49Smrg/** 70132001f49Smrg * Generate display lists for engine parts. 70232001f49Smrg */ 70332001f49Smrgstatic void 70432001f49SmrgGenerateDisplayLists(Engine *eng) 70532001f49Smrg{ 70632001f49Smrg eng->CrankList = glGenLists(1); 70732001f49Smrg glNewList(eng->CrankList, GL_COMPILE); 70832001f49Smrg DrawCrankshaft(eng); 70932001f49Smrg glEndList(); 71032001f49Smrg 71132001f49Smrg eng->ConnRodList = glGenLists(1); 71232001f49Smrg glNewList(eng->ConnRodList, GL_COMPILE); 71332001f49Smrg DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness, 71432001f49Smrg eng->CrankPinRadius, eng->WristPinRadius); 71532001f49Smrg glEndList(); 71632001f49Smrg 71732001f49Smrg eng->PistonList = glGenLists(1); 71832001f49Smrg glNewList(eng->PistonList, GL_COMPILE); 71932001f49Smrg DrawPiston(eng); 72032001f49Smrg glEndList(); 72132001f49Smrg 72232001f49Smrg eng->BlockList = glGenLists(1); 72332001f49Smrg glNewList(eng->BlockList, GL_COMPILE); 72432001f49Smrg DrawEngineBlock(eng); 72532001f49Smrg glEndList(); 72632001f49Smrg} 72732001f49Smrg 72832001f49Smrg 72932001f49Smrg/** 73032001f49Smrg * Free engine display lists (render with immediate mode). 73132001f49Smrg */ 73232001f49Smrgstatic void 73332001f49SmrgFreeDisplayLists(Engine *eng) 73432001f49Smrg{ 73532001f49Smrg glDeleteLists(eng->CrankList, 1); 73632001f49Smrg eng->CrankList = 0; 73732001f49Smrg glDeleteLists(eng->ConnRodList, 1); 73832001f49Smrg eng->ConnRodList = 0; 73932001f49Smrg glDeleteLists(eng->PistonList, 1); 74032001f49Smrg eng->PistonList = 0; 74132001f49Smrg glDeleteLists(eng->BlockList, 1); 74232001f49Smrg eng->BlockList = 0; 74332001f49Smrg} 74432001f49Smrg 74532001f49Smrg 74632001f49Smrg/** 74732001f49Smrg * Draw complete engine. 74832001f49Smrg * \param eng description of engine to draw 74932001f49Smrg * \param crankAngle current crankshaft angle, in radians 75032001f49Smrg */ 75132001f49Smrgstatic void 75232001f49SmrgDrawEngine(const Engine *eng, float crankAngle) 75332001f49Smrg{ 75432001f49Smrg const float crankDelta = 360.0 / eng->Cranks; 75532001f49Smrg const float crankLen = CrankshaftLength(eng); 75632001f49Smrg const int pistonsPerCrank = eng->Pistons / eng->Cranks; 75732001f49Smrg int i; 75832001f49Smrg 75932001f49Smrg glPushMatrix(); 76032001f49Smrg glRotatef(eng->V_Angle * 0.5, 0, 0, 1); 76132001f49Smrg glTranslatef(0, 0, -0.5 * crankLen); 76232001f49Smrg 76332001f49Smrg /* crankshaft */ 76432001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, CrankshaftColor); 76532001f49Smrg glColor4fv(CrankshaftColor); 76632001f49Smrg DrawPositionedCrankshaft(eng, crankAngle); 76732001f49Smrg 76832001f49Smrg for (i = 0; i < eng->Pistons; i++) { 76932001f49Smrg const float z = PistonShaftPosition(eng, i); 77032001f49Smrg const int crank = i / pistonsPerCrank; 77132001f49Smrg float rot = crankAngle + crank * crankDelta; 77232001f49Smrg int k; 77332001f49Smrg 77432001f49Smrg glPushMatrix(); 77532001f49Smrg glTranslatef(0, 0, z); 77632001f49Smrg 77732001f49Smrg /* additional rotation for kth piston per crank */ 77832001f49Smrg k = i % pistonsPerCrank; 77932001f49Smrg glRotatef(k * -eng->V_Angle, 0, 0, 1); 78032001f49Smrg rot += k * eng->V_Angle; 78132001f49Smrg 78232001f49Smrg /* piston */ 78332001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, PistonColor); 78432001f49Smrg glColor4fv(PistonColor); 78532001f49Smrg DrawPositionedPiston(eng, rot); 78632001f49Smrg 78732001f49Smrg /* connecting rod */ 78832001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ConnRodColor); 78932001f49Smrg glColor4fv(ConnRodColor); 79032001f49Smrg DrawPositionedConnectingRod(eng, rot); 79132001f49Smrg glPopMatrix(); 79232001f49Smrg } 79332001f49Smrg 79432001f49Smrg if (Render.ShowBlock) { 79532001f49Smrg const GLboolean blend = glIsEnabled(GL_BLEND); 79632001f49Smrg 79732001f49Smrg glDepthMask(GL_FALSE); 79832001f49Smrg if (!blend) { 79932001f49Smrg glEnable(GL_BLEND); 80032001f49Smrg } 80132001f49Smrg glEnable(GL_CULL_FACE); 80232001f49Smrg 80332001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, BlockColor); 80432001f49Smrg glColor4fv(BlockColor); 80532001f49Smrg if (eng->CrankList) 80632001f49Smrg glCallList(eng->BlockList); 80732001f49Smrg else 80832001f49Smrg DrawEngineBlock(eng); 80932001f49Smrg 81032001f49Smrg glDisable(GL_CULL_FACE); 81132001f49Smrg glDepthMask(GL_TRUE); 81232001f49Smrg if (!blend) { 81332001f49Smrg glDisable(GL_BLEND); 81432001f49Smrg } 81532001f49Smrg } 81632001f49Smrg 81732001f49Smrg glPopMatrix(); 81832001f49Smrg} 81932001f49Smrg 82032001f49Smrg 82132001f49Smrgstatic void 82232001f49SmrgDrawBox(void) 82332001f49Smrg{ 82432001f49Smrg const float xmin = -3.0, xmax = 3.0; 82532001f49Smrg const float ymin = -1.0, ymax = 3.0; 82632001f49Smrg const float zmin = -4.0, zmax = 4.0; 82732001f49Smrg const float step = 0.5; 82832001f49Smrg const float d = 0.01; 82932001f49Smrg float x, y, z; 83032001f49Smrg GLboolean lit = glIsEnabled(GL_LIGHTING); 83132001f49Smrg GLboolean tex = glIsEnabled(GL_TEXTURE_2D); 83232001f49Smrg 83332001f49Smrg glDisable(GL_LIGHTING); 83432001f49Smrg glDisable(GL_TEXTURE_2D); 83532001f49Smrg glLineWidth(1.0); 83632001f49Smrg 83732001f49Smrg glColor3f(1, 1, 1); 83832001f49Smrg 83932001f49Smrg /* Z min */ 84032001f49Smrg glBegin(GL_LINES); 84132001f49Smrg for (x = xmin; x <= xmax; x += step) { 84232001f49Smrg glVertex3f(x, ymin, zmin); 84332001f49Smrg glVertex3f(x, ymax, zmin); 84432001f49Smrg } 84532001f49Smrg glEnd(); 84632001f49Smrg glBegin(GL_LINES); 84732001f49Smrg for (y = ymin; y <= ymax; y += step) { 84832001f49Smrg glVertex3f(xmin, y, zmin); 84932001f49Smrg glVertex3f(xmax, y, zmin); 85032001f49Smrg } 85132001f49Smrg glEnd(); 85232001f49Smrg 85332001f49Smrg /* Y min */ 85432001f49Smrg glBegin(GL_LINES); 85532001f49Smrg for (x = xmin; x <= xmax; x += step) { 85632001f49Smrg glVertex3f(x, ymin, zmin); 85732001f49Smrg glVertex3f(x, ymin, zmax); 85832001f49Smrg } 85932001f49Smrg glEnd(); 86032001f49Smrg glBegin(GL_LINES); 86132001f49Smrg for (z = zmin; z <= zmax; z += step) { 86232001f49Smrg glVertex3f(xmin, ymin, z); 86332001f49Smrg glVertex3f(xmax, ymin, z); 86432001f49Smrg } 86532001f49Smrg glEnd(); 86632001f49Smrg 86732001f49Smrg /* X min */ 86832001f49Smrg glBegin(GL_LINES); 86932001f49Smrg for (y = ymin; y <= ymax; y += step) { 87032001f49Smrg glVertex3f(xmin, y, zmin); 87132001f49Smrg glVertex3f(xmin, y, zmax); 87232001f49Smrg } 87332001f49Smrg glEnd(); 87432001f49Smrg glBegin(GL_LINES); 87532001f49Smrg for (z = zmin; z <= zmax; z += step) { 87632001f49Smrg glVertex3f(xmin, ymin, z); 87732001f49Smrg glVertex3f(xmin, ymax, z); 87832001f49Smrg } 87932001f49Smrg glEnd(); 88032001f49Smrg 88132001f49Smrg glColor3f(0.4, 0.4, 0.6); 88232001f49Smrg glBegin(GL_QUADS); 88332001f49Smrg /* xmin */ 88432001f49Smrg glVertex3f(xmin-d, ymin, zmin); 88532001f49Smrg glVertex3f(xmin-d, ymax, zmin); 88632001f49Smrg glVertex3f(xmin-d, ymax, zmax); 88732001f49Smrg glVertex3f(xmin-d, ymin, zmax); 88832001f49Smrg /* ymin */ 88932001f49Smrg glVertex3f(xmin, ymin-d, zmin); 89032001f49Smrg glVertex3f(xmax, ymin-d, zmin); 89132001f49Smrg glVertex3f(xmax, ymin-d, zmax); 89232001f49Smrg glVertex3f(xmin, ymin-d, zmax); 89332001f49Smrg /* zmin */ 89432001f49Smrg glVertex3f(xmin, ymin, zmin-d); 89532001f49Smrg glVertex3f(xmax, ymin, zmin-d); 89632001f49Smrg glVertex3f(xmax, ymax, zmin-d); 89732001f49Smrg glVertex3f(xmin, ymax, zmin-d); 89832001f49Smrg glEnd(); 89932001f49Smrg 90032001f49Smrg if (lit) 90132001f49Smrg glEnable(GL_LIGHTING); 90232001f49Smrg if (tex) 90332001f49Smrg glEnable(GL_TEXTURE_2D); 90432001f49Smrg} 90532001f49Smrg 90632001f49Smrg 90732001f49Smrgstatic void 90832001f49SmrgPrintString(const char *s) 90932001f49Smrg{ 91032001f49Smrg while (*s) { 91132001f49Smrg glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s); 91232001f49Smrg s++; 91332001f49Smrg } 91432001f49Smrg} 91532001f49Smrg 91632001f49Smrg 91732001f49Smrgstatic int 91832001f49SmrgComputeFPS(void) 91932001f49Smrg{ 92032001f49Smrg static double t0 = -1.0; 92132001f49Smrg static int frames = 0; 92232001f49Smrg double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 92332001f49Smrg static int fps = 0; 92432001f49Smrg 92532001f49Smrg frames++; 92632001f49Smrg 92732001f49Smrg if (t0 < 0.0) { 92832001f49Smrg t0 = t; 92932001f49Smrg fps = 0; 93032001f49Smrg } 93132001f49Smrg else if (t - t0 >= 1.0) { 93232001f49Smrg fps = (int) (frames / (t - t0) + 0.5); 93332001f49Smrg t0 = t; 93432001f49Smrg frames = 0; 93532001f49Smrg } 93632001f49Smrg 93732001f49Smrg return fps; 93832001f49Smrg} 93932001f49Smrg 94032001f49Smrg 94132001f49Smrgstatic void 94232001f49SmrgDraw(void) 94332001f49Smrg{ 94432001f49Smrg int fps; 94532001f49Smrg GLfloat rot[4][4]; 94632001f49Smrg 94732001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 94832001f49Smrg 94932001f49Smrg glPushMatrix(); 95032001f49Smrg 95132001f49Smrg glTranslatef(0.0, 0.0, -View.Distance); 95232001f49Smrg build_rotmatrix(rot, View.CurQuat); 95332001f49Smrg glMultMatrixf(&rot[0][0]); 95432001f49Smrg 95532001f49Smrg glPushMatrix(); 95632001f49Smrg glTranslatef(0, -0.75, 0); 95732001f49Smrg if (Render.DrawBox) 95832001f49Smrg DrawBox(); 95932001f49Smrg DrawEngine(Engines + CurEngine, Theta); 96032001f49Smrg glPopMatrix(); 96132001f49Smrg 96232001f49Smrg glPopMatrix(); 96332001f49Smrg 96432001f49Smrg fps = ComputeFPS(); 96532001f49Smrg if (Render.ShowInfo) { 96632001f49Smrg GLboolean lit = glIsEnabled(GL_LIGHTING); 96732001f49Smrg GLboolean tex = glIsEnabled(GL_TEXTURE_2D); 96832001f49Smrg char s[100]; 96932001f49Smrg sprintf(s, "%s %d FPS %s", Engines[CurEngine].Name, fps, 97032001f49Smrg Render.UseLists ? "Display Lists" : "Immediate mode"); 97132001f49Smrg glDisable(GL_LIGHTING); 97232001f49Smrg glDisable(GL_TEXTURE_2D); 97332001f49Smrg glColor3f(1, 1 , 1); 97432001f49Smrg glWindowPos2iARB(10, 10); 97532001f49Smrg PrintString(s); 97632001f49Smrg if (lit) 97732001f49Smrg glEnable(GL_LIGHTING); 97832001f49Smrg if (tex) 97932001f49Smrg glEnable(GL_TEXTURE_2D); 98032001f49Smrg } 98132001f49Smrg 98232001f49Smrg /* also print out a periodic fps to stdout. useful for trying to 98332001f49Smrg * figure out the performance impact of rendering the string above 98432001f49Smrg * with glBitmap. 98532001f49Smrg */ 98632001f49Smrg { 98732001f49Smrg static GLint T0 = 0; 98832001f49Smrg static GLint Frames = 0; 98932001f49Smrg GLint t = glutGet(GLUT_ELAPSED_TIME); 99032001f49Smrg 99132001f49Smrg Frames++; 99232001f49Smrg 99332001f49Smrg if (t - T0 >= 5000) { 99432001f49Smrg GLfloat seconds = (t - T0) / 1000.0; 99532001f49Smrg GLfloat fps = Frames / seconds; 99632001f49Smrg printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps); 99732001f49Smrg fflush(stdout); 99832001f49Smrg T0 = t; 99932001f49Smrg Frames = 0; 100032001f49Smrg } 100132001f49Smrg } 100232001f49Smrg 100332001f49Smrg 100432001f49Smrg glutSwapBuffers(); 100532001f49Smrg} 100632001f49Smrg 100732001f49Smrg 100832001f49Smrg/** 100932001f49Smrg * Handle window resize. 101032001f49Smrg */ 101132001f49Smrgstatic void 101232001f49SmrgReshape(int width, int height) 101332001f49Smrg{ 101432001f49Smrg float ar = (float) width / height; 101532001f49Smrg float s = 0.5; 101632001f49Smrg glViewport(0, 0, width, height); 101732001f49Smrg glMatrixMode(GL_PROJECTION); 101832001f49Smrg glLoadIdentity(); 101932001f49Smrg glFrustum(-ar * s, ar * s, -s, s, 2.0, 50.0); 102032001f49Smrg glMatrixMode(GL_MODELVIEW); 102132001f49Smrg glLoadIdentity(); 102232001f49Smrg WinWidth = width; 102332001f49Smrg WinHeight = height; 102432001f49Smrg} 102532001f49Smrg 102632001f49Smrg 102732001f49Smrg/** 102832001f49Smrg * Handle mouse button. 102932001f49Smrg */ 103032001f49Smrgstatic void 103132001f49SmrgMouse(int button, int state, int x, int y) 103232001f49Smrg{ 103332001f49Smrg if (button == GLUT_LEFT_BUTTON) { 103432001f49Smrg if (state == GLUT_DOWN) { 103532001f49Smrg View.StartX = x; 103632001f49Smrg View.StartY = y; 103732001f49Smrg View.Rotating = GL_TRUE; 103832001f49Smrg } 103932001f49Smrg else if (state == GLUT_UP) { 104032001f49Smrg View.Rotating = GL_FALSE; 104132001f49Smrg } 104232001f49Smrg } 104332001f49Smrg else if (button == GLUT_MIDDLE_BUTTON) { 104432001f49Smrg if (state == GLUT_DOWN) { 104532001f49Smrg View.StartX = x; 104632001f49Smrg View.StartY = y; 104732001f49Smrg View.StartDistance = View.Distance; 104832001f49Smrg View.Translating = GL_TRUE; 104932001f49Smrg } 105032001f49Smrg else if (state == GLUT_UP) { 105132001f49Smrg View.Translating = GL_FALSE; 105232001f49Smrg } 105332001f49Smrg } 105432001f49Smrg} 105532001f49Smrg 105632001f49Smrg 105732001f49Smrg/** 105832001f49Smrg * Handle mouse motion 105932001f49Smrg */ 106032001f49Smrgstatic void 106132001f49SmrgMotion(int x, int y) 106232001f49Smrg{ 106332001f49Smrg int i; 106432001f49Smrg if (View.Rotating) { 106532001f49Smrg float x0 = (2.0 * View.StartX - WinWidth) / WinWidth; 106632001f49Smrg float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight; 106732001f49Smrg float x1 = (2.0 * x - WinWidth) / WinWidth; 106832001f49Smrg float y1 = (WinHeight - 2.0 * y) / WinHeight; 106932001f49Smrg float q[4]; 107032001f49Smrg 107132001f49Smrg trackball(q, x0, y0, x1, y1); 107232001f49Smrg View.StartX = x; 107332001f49Smrg View.StartY = y; 107432001f49Smrg for (i = 0; i < 1; i++) 107532001f49Smrg add_quats(q, View.CurQuat, View.CurQuat); 107632001f49Smrg 107732001f49Smrg glutPostRedisplay(); 107832001f49Smrg } 107932001f49Smrg else if (View.Translating) { 108032001f49Smrg float dz = 0.01 * (y - View.StartY); 108132001f49Smrg View.Distance = View.StartDistance + dz; 108232001f49Smrg glutPostRedisplay(); 108332001f49Smrg } 108432001f49Smrg} 108532001f49Smrg 108632001f49Smrg 108732001f49Smrg/** 108832001f49Smrg ** Menu Callbacks 108932001f49Smrg **/ 109032001f49Smrg 109132001f49Smrgstatic void 109232001f49SmrgOptAnimation(void) 109332001f49Smrg{ 109432001f49Smrg Render.Anim = !Render.Anim; 109532001f49Smrg if (Render.Anim) 109632001f49Smrg glutIdleFunc(Idle); 109732001f49Smrg else 109832001f49Smrg glutIdleFunc(NULL); 109932001f49Smrg} 110032001f49Smrg 110132001f49Smrgstatic void 110232001f49SmrgOptChangeEngine(void) 110332001f49Smrg{ 110432001f49Smrg CurEngine = (CurEngine + 1) % NUM_ENGINES; 110532001f49Smrg} 110632001f49Smrg 110732001f49Smrgstatic void 110832001f49SmrgOptRenderMode(void) 110932001f49Smrg{ 111032001f49Smrg Render.Mode++; 111132001f49Smrg if (Render.Mode > TEXTURED) 111232001f49Smrg Render.Mode = 0; 111332001f49Smrg SetRenderState(Render.Mode); 111432001f49Smrg} 111532001f49Smrg 111632001f49Smrgstatic void 111732001f49SmrgOptDisplayLists(void) 111832001f49Smrg{ 111932001f49Smrg int i; 112032001f49Smrg Render.UseLists = !Render.UseLists; 112132001f49Smrg if (Render.UseLists) { 112232001f49Smrg for (i = 0; i < NUM_ENGINES; i++) { 112332001f49Smrg GenerateDisplayLists(Engines + i); 112432001f49Smrg } 112532001f49Smrg } 112632001f49Smrg else { 112732001f49Smrg for (i = 0; i < NUM_ENGINES; i++) { 112832001f49Smrg FreeDisplayLists(Engines + i); 112932001f49Smrg } 113032001f49Smrg } 113132001f49Smrg} 113232001f49Smrg 113332001f49Smrgstatic void 113432001f49SmrgOptShowBlock(void) 113532001f49Smrg{ 113632001f49Smrg Render.ShowBlock = !Render.ShowBlock; 113732001f49Smrg} 113832001f49Smrg 113932001f49Smrgstatic void 114032001f49SmrgOptShowInfo(void) 114132001f49Smrg{ 114232001f49Smrg Render.ShowInfo = !Render.ShowInfo; 114332001f49Smrg} 114432001f49Smrg 114532001f49Smrgstatic void 114632001f49SmrgOptShowBox(void) 114732001f49Smrg{ 114832001f49Smrg Render.DrawBox = !Render.DrawBox; 114932001f49Smrg} 115032001f49Smrg 115132001f49Smrgstatic void 115232001f49SmrgOptRotate(void) 115332001f49Smrg{ 115432001f49Smrg Theta += 5.0; 115532001f49Smrg} 115632001f49Smrg 115732001f49Smrgstatic void 115832001f49SmrgOptExit(void) 115932001f49Smrg{ 116032001f49Smrg glutDestroyWindow(Win); 116132001f49Smrg exit(0); 116232001f49Smrg} 116332001f49Smrg 116432001f49Smrg 116532001f49Smrg/** 116632001f49Smrg * Define menu entries (w/ keyboard shortcuts) 116732001f49Smrg */ 116832001f49Smrg 116932001f49Smrgtypedef struct 117032001f49Smrg{ 117132001f49Smrg const char *Text; 117232001f49Smrg const char Key; 117332001f49Smrg void (*Function)(void); 117432001f49Smrg} MenuInfo; 117532001f49Smrg 117632001f49Smrgstatic const MenuInfo MenuItems[] = { 117732001f49Smrg { "Animation", 'a', OptAnimation }, 117832001f49Smrg { "Change Engine", 'e', OptChangeEngine }, 117932001f49Smrg { "Rendering Style", 'm', OptRenderMode }, 118032001f49Smrg { "Display Lists", 'd', OptDisplayLists }, 118132001f49Smrg { "Show Block", 'b', OptShowBlock }, 118232001f49Smrg { "Show Info", 'i', OptShowInfo }, 118332001f49Smrg { "Show Box", 'x', OptShowBox }, 118432001f49Smrg { "Exit", 27, OptExit }, 118532001f49Smrg { NULL, 'r', OptRotate }, 118632001f49Smrg { NULL, 0, NULL } 118732001f49Smrg}; 118832001f49Smrg 118932001f49Smrg 119032001f49Smrg/** 119132001f49Smrg * Handle menu selection. 119232001f49Smrg */ 119332001f49Smrgstatic void 119432001f49SmrgMenuHandler(int entry) 119532001f49Smrg{ 119632001f49Smrg MenuItems[entry].Function(); 119732001f49Smrg glutPostRedisplay(); 119832001f49Smrg} 119932001f49Smrg 120032001f49Smrg 120132001f49Smrg/** 120232001f49Smrg * Make pop-up menu. 120332001f49Smrg */ 120432001f49Smrgstatic void 120532001f49SmrgMakeMenu(void) 120632001f49Smrg{ 120732001f49Smrg int i; 120832001f49Smrg glutCreateMenu(MenuHandler); 120932001f49Smrg for (i = 0; MenuItems[i].Text; i++) { 121032001f49Smrg glutAddMenuEntry(MenuItems[i].Text, i); 121132001f49Smrg } 121232001f49Smrg glutAttachMenu(GLUT_RIGHT_BUTTON); 121332001f49Smrg} 121432001f49Smrg 121532001f49Smrg 121632001f49Smrg/** 121732001f49Smrg * Handle keyboard event. 121832001f49Smrg */ 121932001f49Smrgstatic void 122032001f49SmrgKey(unsigned char key, int x, int y) 122132001f49Smrg{ 122232001f49Smrg int i; 122332001f49Smrg (void) x; (void) y; 122432001f49Smrg for (i = 0; MenuItems[i].Key; i++) { 122532001f49Smrg if (MenuItems[i].Key == key) { 122632001f49Smrg MenuItems[i].Function(); 122732001f49Smrg glutPostRedisplay(); 122832001f49Smrg break; 122932001f49Smrg } 123032001f49Smrg } 123132001f49Smrg} 123232001f49Smrg 123332001f49Smrg 123432001f49Smrgstatic 123532001f49Smrgvoid LoadTexture(void) 123632001f49Smrg{ 123732001f49Smrg GLboolean convolve = GL_FALSE; 123832001f49Smrg 123932001f49Smrg glGenTextures(1, &TextureObj); 124032001f49Smrg glBindTexture(GL_TEXTURE_2D, TextureObj); 124132001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 124232001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 124332001f49Smrg glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 124432001f49Smrg glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 124532001f49Smrg 124632001f49Smrg if (convolve) { 124732001f49Smrg#define FILTER_SIZE 7 124832001f49Smrg /* use convolution to blur the texture to simulate a dull finish 124932001f49Smrg * on the object. 125032001f49Smrg */ 125132001f49Smrg GLubyte *img; 125232001f49Smrg GLenum format; 125332001f49Smrg GLint w, h; 125432001f49Smrg GLfloat filter[FILTER_SIZE][FILTER_SIZE][4]; 125532001f49Smrg 125632001f49Smrg for (h = 0; h < FILTER_SIZE; h++) { 125732001f49Smrg for (w = 0; w < FILTER_SIZE; w++) { 125832001f49Smrg const GLfloat k = 1.0 / (FILTER_SIZE * FILTER_SIZE); 125932001f49Smrg filter[h][w][0] = k; 126032001f49Smrg filter[h][w][1] = k; 126132001f49Smrg filter[h][w][2] = k; 126232001f49Smrg filter[h][w][3] = k; 126332001f49Smrg } 126432001f49Smrg } 126532001f49Smrg 126632001f49Smrg glEnable(GL_CONVOLUTION_2D); 126732001f49Smrg glConvolutionParameteri(GL_CONVOLUTION_2D, 126832001f49Smrg GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER); 126932001f49Smrg glConvolutionFilter2D(GL_CONVOLUTION_2D, GL_RGBA, 127032001f49Smrg FILTER_SIZE, FILTER_SIZE, 127132001f49Smrg GL_RGBA, GL_FLOAT, filter); 127232001f49Smrg 127332001f49Smrg img = LoadRGBImage(TEXTURE_FILE, &w, &h, &format); 127432001f49Smrg if (!img) { 127532001f49Smrg printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE); 127632001f49Smrg exit(1); 127732001f49Smrg } 127832001f49Smrg 127932001f49Smrg glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, 128032001f49Smrg format, GL_UNSIGNED_BYTE, img); 128132001f49Smrg free(img); 128232001f49Smrg } 128332001f49Smrg else { 128432001f49Smrg if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) { 128532001f49Smrg printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE); 128632001f49Smrg exit(1); 128732001f49Smrg } 128832001f49Smrg } 128932001f49Smrg} 129032001f49Smrg 129132001f49Smrg 129232001f49Smrgstatic void 129332001f49SmrgInit(void) 129432001f49Smrg{ 129532001f49Smrg const GLfloat lightColor[4] = { 0.7, 0.7, 0.7, 1.0 }; 129632001f49Smrg const GLfloat specular[4] = { 0.8, 0.8, 0.8, 1.0 }; 129732001f49Smrg const GLfloat backColor[4] = { 1, 1, 0, 0 }; 129832001f49Smrg 129932001f49Smrg Q = gluNewQuadric(); 130032001f49Smrg gluQuadricNormals(Q, GLU_SMOOTH); 130132001f49Smrg 130232001f49Smrg LoadTexture(); 130332001f49Smrg 130432001f49Smrg glClearColor(0.3, 0.3, 0.3, 0.0); 130532001f49Smrg glEnable(GL_DEPTH_TEST); 130632001f49Smrg glEnable(GL_LIGHTING); 130732001f49Smrg glEnable(GL_LIGHT0); 130832001f49Smrg glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); 130932001f49Smrg glMaterialf(GL_FRONT, GL_SHININESS, 40); 131032001f49Smrg glMaterialfv(GL_FRONT, GL_SPECULAR, specular); 131132001f49Smrg glEnable(GL_NORMALIZE); 131232001f49Smrg 131332001f49Smrg glMaterialfv(GL_BACK, GL_DIFFUSE, backColor); 131432001f49Smrg#if 0 131532001f49Smrg glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); 131632001f49Smrg#endif 131732001f49Smrg glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 131832001f49Smrg 131932001f49Smrg InitViewInfo(&View); 132032001f49Smrg InitRenderInfo(&Render); 132132001f49Smrg} 132232001f49Smrg 132332001f49Smrg 132432001f49Smrgint 132532001f49Smrgmain(int argc, char *argv[]) 132632001f49Smrg{ 132732001f49Smrg glutInitWindowSize(WinWidth, WinHeight); 132832001f49Smrg glutInit(&argc, argv); 132932001f49Smrg glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 133032001f49Smrg Win = glutCreateWindow("OpenGL Engine Demo"); 133132001f49Smrg glewInit(); 133232001f49Smrg glutReshapeFunc(Reshape); 133332001f49Smrg glutMouseFunc(Mouse); 133432001f49Smrg glutMotionFunc(Motion); 133532001f49Smrg glutKeyboardFunc(Key); 133632001f49Smrg glutDisplayFunc(Draw); 133732001f49Smrg MakeMenu(); 133832001f49Smrg Init(); 133932001f49Smrg if (Render.Anim) 134032001f49Smrg glutIdleFunc(Idle); 134132001f49Smrg glutMainLoop(); 134232001f49Smrg return 0; 134332001f49Smrg} 1344