1677 lines
40 KiB
C
1677 lines
40 KiB
C
|
/*
|
||
|
* Demo of off-screen Mesa rendering
|
||
|
*
|
||
|
* See Mesa/include/GL/osmesa.h for documentation of the OSMesa functions.
|
||
|
*
|
||
|
* If you want to render BIG images you'll probably have to increase
|
||
|
* MAX_WIDTH and MAX_Height in src/config.h.
|
||
|
*
|
||
|
* This program is in the public domain.
|
||
|
*
|
||
|
* Brian Paul
|
||
|
*
|
||
|
* PPM output provided by Joerg Schmalzl.
|
||
|
* ASCII PPM output added by Brian Paul.
|
||
|
*
|
||
|
* Usage: osdemo [filename]
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <math.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <assert.h>
|
||
|
#define GL_GLEXT_PROTOTYPES
|
||
|
#include "GL/osmesa.h"
|
||
|
#include <GL/glext.h>
|
||
|
#include "GL/glu.h"
|
||
|
#include "shaderutil.h"
|
||
|
|
||
|
|
||
|
static int Width = 500;
|
||
|
static int Height = 400;
|
||
|
|
||
|
int check_events();
|
||
|
|
||
|
GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
|
||
|
GLfloat angle = 0.0;
|
||
|
|
||
|
GLboolean animate = GL_TRUE; /* Animation */
|
||
|
GLfloat eyesep = 5.0; /* Eye separation. */
|
||
|
GLfloat fix_point = 40.0; /* Fixation point distance. */
|
||
|
GLfloat left, right, asp; /* Stereo frustum params. */
|
||
|
|
||
|
void init( void );
|
||
|
void reshape( int width, int height );
|
||
|
void draw( void );
|
||
|
void idle();
|
||
|
void Key(unsigned char key, int x, int y);
|
||
|
|
||
|
typedef union __attribute__((packed))
|
||
|
{
|
||
|
uint32_t val;
|
||
|
struct
|
||
|
{
|
||
|
uint8_t state;
|
||
|
uint8_t code;
|
||
|
uint16_t ctrl_key;
|
||
|
};
|
||
|
}oskey_t;
|
||
|
|
||
|
static inline oskey_t get_key(void)
|
||
|
{
|
||
|
oskey_t val;
|
||
|
__asm__ __volatile__(
|
||
|
"int $0x40"
|
||
|
:"=eax"(val)
|
||
|
:"a"(2));
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct blit_call
|
||
|
{
|
||
|
int dstx;
|
||
|
int dsty;
|
||
|
int w;
|
||
|
int h;
|
||
|
|
||
|
int srcx;
|
||
|
int srcy;
|
||
|
int srcw;
|
||
|
int srch;
|
||
|
|
||
|
unsigned char *bitmap;
|
||
|
int stride;
|
||
|
};
|
||
|
|
||
|
static inline uint32_t wait_os_event(int time)
|
||
|
{
|
||
|
uint32_t val;
|
||
|
__asm__ __volatile__(
|
||
|
"int $0x40"
|
||
|
:"=a"(val)
|
||
|
:"a"(23),"b"(time));
|
||
|
return val;
|
||
|
};
|
||
|
|
||
|
static inline uint32_t get_os_button()
|
||
|
{
|
||
|
uint32_t val;
|
||
|
__asm__ __volatile__(
|
||
|
"int $0x40"
|
||
|
:"=a"(val)
|
||
|
:"a"(17));
|
||
|
return val>>8;
|
||
|
};
|
||
|
|
||
|
static inline void DrawWindow(int x, int y, int w, int h, char *name,
|
||
|
uint32_t workcolor, uint32_t style)
|
||
|
{
|
||
|
|
||
|
__asm__ __volatile__(
|
||
|
"int $0x40"
|
||
|
::"a"(0),
|
||
|
"b"((x << 16) | (w & 0xFFFF)),
|
||
|
"c"((y << 16) | (h & 0xFFFF)),
|
||
|
"d"((style << 24) | (workcolor & 0xFFFFFF)),
|
||
|
"D"(name));
|
||
|
};
|
||
|
|
||
|
static inline void Blit(void *bitmap, int dst_x, int dst_y,
|
||
|
int src_x, int src_y, int w, int h,
|
||
|
int src_w, int src_h, int stride)
|
||
|
{
|
||
|
volatile struct blit_call bc;
|
||
|
|
||
|
bc.dstx = dst_x;
|
||
|
bc.dsty = dst_y;
|
||
|
bc.w = w;
|
||
|
bc.h = h;
|
||
|
bc.srcx = src_x;
|
||
|
bc.srcy = src_y;
|
||
|
bc.srcw = src_w;
|
||
|
bc.srch = src_h;
|
||
|
bc.stride = stride;
|
||
|
bc.bitmap = bitmap;
|
||
|
|
||
|
__asm__ __volatile__(
|
||
|
"int $0x40"
|
||
|
::"a"(73),"b"(0),"c"(&bc.dstx));
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
#define XK_Left 176
|
||
|
#define XK_Right 179
|
||
|
#define XK_Up 178
|
||
|
#define XK_Down 177
|
||
|
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
OSMesaContext ctx;
|
||
|
void *buffer;
|
||
|
char *filename = NULL;
|
||
|
int ev;
|
||
|
int repeat=1;
|
||
|
|
||
|
/* Create an RGBA-mode context */
|
||
|
/* specify Z, stencil, accum sizes */
|
||
|
|
||
|
ctx = OSMesaCreateContextExt( OSMESA_RGBA, 16, 0, 0, NULL );
|
||
|
if (!ctx) {
|
||
|
printf("OSMesaCreateContext failed!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Allocate the image buffer */
|
||
|
buffer = malloc( Width * Height * 4 * sizeof(GLubyte) );
|
||
|
if (!buffer) {
|
||
|
printf("Alloc image buffer failed!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// __asm__ __volatile__("int3");
|
||
|
|
||
|
/* Bind the buffer to the context and make it current */
|
||
|
if (!OSMesaMakeCurrent( ctx, buffer, GL_UNSIGNED_BYTE, Width, Height )) {
|
||
|
printf("OSMesaMakeCurrent failed!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
int z, s, a;
|
||
|
glGetIntegerv(GL_DEPTH_BITS, &z);
|
||
|
glGetIntegerv(GL_STENCIL_BITS, &s);
|
||
|
glGetIntegerv(GL_ACCUM_RED_BITS, &a);
|
||
|
printf("Depth=%d Stencil=%d Accum=%d\n", z, s, a);
|
||
|
}
|
||
|
|
||
|
reshape(Width, Height);
|
||
|
|
||
|
init();
|
||
|
draw();
|
||
|
|
||
|
printf("all done\n");
|
||
|
|
||
|
DrawWindow(10, 10, Width+9, Height+26, "OpenGL Engine Demo", 0x000000, 0x74);
|
||
|
Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
|
||
|
|
||
|
while(repeat)
|
||
|
{
|
||
|
oskey_t key;
|
||
|
|
||
|
ev = wait_os_event(1);
|
||
|
switch(ev)
|
||
|
{
|
||
|
case 1:
|
||
|
DrawWindow(10, 10, Width+9, Width+26, NULL, 0x000000,0x74);
|
||
|
Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
|
||
|
continue;
|
||
|
|
||
|
case 2:
|
||
|
key = get_key();
|
||
|
Key(key.code, 0, 0);
|
||
|
draw();
|
||
|
Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
|
||
|
continue;
|
||
|
|
||
|
case 3:
|
||
|
if(get_os_button()==1)
|
||
|
repeat=0;
|
||
|
continue;
|
||
|
};
|
||
|
|
||
|
idle();
|
||
|
|
||
|
// angle += 70.0 * 0.05; /* 70 degrees per second */
|
||
|
// if (angle > 3600.0)
|
||
|
// angle -= 3600.0;
|
||
|
draw();
|
||
|
Blit(buffer, 5, 22, 0, 0, Width, Height, Width,Height,Width*4);
|
||
|
};
|
||
|
|
||
|
/* free the image buffer */
|
||
|
free( buffer );
|
||
|
|
||
|
/* destroy the context */
|
||
|
OSMesaDestroyContext( ctx );
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void exit(int code)
|
||
|
{
|
||
|
_exit(code);
|
||
|
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
static char *FragProgFile = "CH11-toyball.frag";
|
||
|
static char *VertProgFile = "CH11-toyball.vert";
|
||
|
|
||
|
/* program/shader objects */
|
||
|
static GLuint fragShader;
|
||
|
static GLuint vertShader;
|
||
|
static GLuint program;
|
||
|
|
||
|
|
||
|
static struct uniform_info Uniforms[] = {
|
||
|
{ "LightDir", 1, GL_FLOAT_VEC4, { 0.57737, 0.57735, 0.57735, 0.0 }, -1 },
|
||
|
{ "HVector", 1, GL_FLOAT_VEC4, { 0.32506, 0.32506, 0.88808, 0.0 }, -1 },
|
||
|
{ "BallCenter", 1, GL_FLOAT_VEC4, { 0.0, 0.0, 0.0, 1.0 }, -1 },
|
||
|
{ "SpecularColor", 1, GL_FLOAT_VEC4, { 0.4, 0.4, 0.4, 60.0 }, -1 },
|
||
|
{ "Red", 1, GL_FLOAT_VEC4, { 0.6, 0.0, 0.0, 1.0 }, -1 },
|
||
|
{ "Blue", 1, GL_FLOAT_VEC4, { 0.0, 0.3, 0.6, 1.0 }, -1 },
|
||
|
{ "Yellow", 1, GL_FLOAT_VEC4, { 0.6, 0.5, 0.0, 1.0 }, -1 },
|
||
|
{ "HalfSpace0", 1, GL_FLOAT_VEC4, { 1.0, 0.0, 0.0, 0.2 }, -1 },
|
||
|
{ "HalfSpace1", 1, GL_FLOAT_VEC4, { 0.309016994, 0.951056516, 0.0, 0.2 }, -1 },
|
||
|
{ "HalfSpace2", 1, GL_FLOAT_VEC4, { -0.809016994, 0.587785252, 0.0, 0.2 }, -1 },
|
||
|
{ "HalfSpace3", 1, GL_FLOAT_VEC4, { -0.809016994, -0.587785252, 0.0, 0.2 }, -1 },
|
||
|
{ "HalfSpace4", 1, GL_FLOAT_VEC4, { 0.309116994, -0.951056516, 0.0, 0.2 }, -1 },
|
||
|
{ "InOrOutInit", 1, GL_FLOAT, { -3.0, 0, 0, 0 }, -1 },
|
||
|
{ "StripeWidth", 1, GL_FLOAT, { 0.3, 0, 0, 0 }, -1 },
|
||
|
{ "FWidth", 1, GL_FLOAT, { 0.005, 0, 0, 0 }, -1 },
|
||
|
END_OF_UNIFORMS
|
||
|
};
|
||
|
|
||
|
static GLint win = 0;
|
||
|
static GLboolean Anim = GL_FALSE;
|
||
|
static GLfloat TexRot = 0.0;
|
||
|
static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
|
||
|
|
||
|
|
||
|
void Idle(void)
|
||
|
{
|
||
|
TexRot += 2.0;
|
||
|
if (TexRot > 360.0)
|
||
|
TexRot -= 360.0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void draw(void)
|
||
|
{
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
|
||
|
glPushMatrix();
|
||
|
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
|
||
|
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
|
||
|
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
|
||
|
|
||
|
glMatrixMode(GL_TEXTURE);
|
||
|
glLoadIdentity();
|
||
|
glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
|
||
|
glutSolidSphere(2.0, 20, 10);
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
reshape(int width, int height)
|
||
|
{
|
||
|
glViewport(0, 0, width, height);
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glLoadIdentity();
|
||
|
glTranslatef(0.0f, 0.0f, -15.0f);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
CleanUp(void)
|
||
|
{
|
||
|
glDeleteShader(fragShader);
|
||
|
glDeleteShader(vertShader);
|
||
|
glDeleteProgram(program);
|
||
|
glutDestroyWindow(win);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void init(void)
|
||
|
{
|
||
|
// if (!ShadersSupported())
|
||
|
// exit(1);
|
||
|
|
||
|
vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertProgFile);
|
||
|
fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragProgFile);
|
||
|
program = LinkShaders(vertShader, fragShader);
|
||
|
|
||
|
glUseProgram(program);
|
||
|
|
||
|
SetUniformValues(program, Uniforms);
|
||
|
PrintUniforms(Uniforms);
|
||
|
|
||
|
assert(glGetError() == 0);
|
||
|
|
||
|
glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
|
||
|
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
|
||
|
glColor3f(1, 0, 0);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
static float Zrot = 0.0;
|
||
|
|
||
|
void draw( void )
|
||
|
{
|
||
|
glClearColor(0.3, 0.3, 0.3, 1);
|
||
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||
|
|
||
|
glEnable(GL_VERTEX_PROGRAM_NV);
|
||
|
|
||
|
glLoadIdentity();
|
||
|
glRotatef(Zrot, 0, 0, 1);
|
||
|
|
||
|
glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW, GL_IDENTITY_NV);
|
||
|
glPushMatrix();
|
||
|
|
||
|
glVertexAttrib3fNV(3, 1, 0.5, 0.25);
|
||
|
glBegin(GL_TRIANGLES);
|
||
|
#if 1
|
||
|
glVertexAttrib3fNV(3, 1.0, 0.0, 0.0);
|
||
|
glVertexAttrib2fNV(0, -0.5, -0.5);
|
||
|
glVertexAttrib3fNV(3, 0.0, 1.0, 0.0);
|
||
|
glVertexAttrib2fNV(0, 0.5, -0.5);
|
||
|
glVertexAttrib3fNV(3, 0.0, 0.0, 1.0);
|
||
|
glVertexAttrib2fNV(0, 0, 0.5);
|
||
|
#else
|
||
|
glVertex2f( -1, -1);
|
||
|
glVertex2f( 1, -1);
|
||
|
glVertex2f( 0, 1);
|
||
|
#endif
|
||
|
glEnd();
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void reshape( int width, int height )
|
||
|
{
|
||
|
glViewport( 0, 0, width, height );
|
||
|
glMatrixMode( GL_PROJECTION );
|
||
|
glLoadIdentity();
|
||
|
/* glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
|
||
|
glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0 );
|
||
|
glMatrixMode( GL_MODELVIEW );
|
||
|
glLoadIdentity();
|
||
|
/*glTranslatef( 0.0, 0.0, -15.0 );*/
|
||
|
}
|
||
|
|
||
|
void idle()
|
||
|
{
|
||
|
Zrot-=4.0;
|
||
|
};
|
||
|
|
||
|
void init( void )
|
||
|
{
|
||
|
static const char *prog1 =
|
||
|
"!!VP1.0\n"
|
||
|
"MOV o[COL0], v[COL0];\n"
|
||
|
#if 0
|
||
|
"MOV o[HPOS], v[OPOS];\n"
|
||
|
#else
|
||
|
"DP4 o[HPOS].x, v[OPOS], c[0];\n"
|
||
|
"DP4 o[HPOS].y, v[OPOS], c[1];\n"
|
||
|
"DP4 o[HPOS].z, v[OPOS], c[2];\n"
|
||
|
"DP4 o[HPOS].w, v[OPOS], c[3];\n"
|
||
|
#endif
|
||
|
"END\n";
|
||
|
|
||
|
// if (!glutExtensionSupported("GL_NV_vertex_program")) {
|
||
|
// printf("Sorry, this program requires GL_NV_vertex_program\n");
|
||
|
// exit(1);
|
||
|
// }
|
||
|
|
||
|
glLoadProgramNV(GL_VERTEX_PROGRAM_NV, 1,
|
||
|
strlen(prog1),
|
||
|
(const GLubyte *) prog1);
|
||
|
assert(glIsProgramNV(1));
|
||
|
|
||
|
glBindProgramNV(GL_VERTEX_PROGRAM_NV, 1);
|
||
|
|
||
|
printf("glGetError = %x\n", (int) glGetError());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef M_PI
|
||
|
#define M_PI 3.14159265358979323846
|
||
|
#endif
|
||
|
|
||
|
#define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.0)
|
||
|
|
||
|
#define TEXTURE_FILE "reflect.rgb"
|
||
|
|
||
|
/* Target engine speed: */
|
||
|
const int RPM = 100.0;
|
||
|
|
||
|
static int Win = 0;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Engine description.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
const char *Name;
|
||
|
int Pistons;
|
||
|
int Cranks;
|
||
|
float V_Angle;
|
||
|
float PistonRadius;
|
||
|
float PistonHeight;
|
||
|
float WristPinRadius;
|
||
|
float Throw;
|
||
|
float CrankPlateThickness;
|
||
|
float CrankPinRadius;
|
||
|
float CrankJournalRadius;
|
||
|
float CrankJournalLength;
|
||
|
float ConnectingRodLength;
|
||
|
float ConnectingRodThickness;
|
||
|
/* display list IDs */
|
||
|
GLuint CrankList;
|
||
|
GLuint ConnRodList;
|
||
|
GLuint PistonList;
|
||
|
GLuint BlockList;
|
||
|
} Engine;
|
||
|
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
float CurQuat[4];
|
||
|
float Distance;
|
||
|
/* When mouse is moving: */
|
||
|
GLboolean Rotating, Translating;
|
||
|
GLint StartX, StartY;
|
||
|
float StartDistance;
|
||
|
} ViewInfo;
|
||
|
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
LIT,
|
||
|
WIREFRAME,
|
||
|
TEXTURED
|
||
|
} RenderMode;
|
||
|
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
RenderMode Mode;
|
||
|
GLboolean Anim;
|
||
|
GLboolean Wireframe;
|
||
|
GLboolean Blend;
|
||
|
GLboolean Antialias;
|
||
|
GLboolean Texture;
|
||
|
GLboolean UseLists;
|
||
|
GLboolean DrawBox;
|
||
|
GLboolean ShowInfo;
|
||
|
GLboolean ShowBlock;
|
||
|
} RenderInfo;
|
||
|
|
||
|
|
||
|
static GLUquadric *Q;
|
||
|
|
||
|
static GLfloat Theta = 0.0;
|
||
|
|
||
|
static const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
|
||
|
static const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
|
||
|
static const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
|
||
|
static const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 };
|
||
|
|
||
|
static GLuint TextureObj;
|
||
|
static GLint WinWidth = 800, WinHeight = 500;
|
||
|
|
||
|
static ViewInfo View;
|
||
|
static RenderInfo Render;
|
||
|
|
||
|
void build_rotmatrix(float m[4][4], const float q[4])
|
||
|
{
|
||
|
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
|
||
|
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
|
||
|
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
|
||
|
m[0][3] = 0.0;
|
||
|
|
||
|
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
|
||
|
m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
|
||
|
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
|
||
|
m[1][3] = 0.0;
|
||
|
|
||
|
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
|
||
|
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
|
||
|
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
|
||
|
m[2][3] = 0.0;
|
||
|
|
||
|
m[3][0] = 0.0;
|
||
|
m[3][1] = 0.0;
|
||
|
m[3][2] = 0.0;
|
||
|
m[3][3] = 1.0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define NUM_ENGINES 3
|
||
|
static Engine Engines[NUM_ENGINES] =
|
||
|
{
|
||
|
{
|
||
|
"V-6",
|
||
|
6, /* Pistons */
|
||
|
3, /* Cranks */
|
||
|
90.0, /* V_Angle */
|
||
|
0.5, /* PistonRadius */
|
||
|
0.6, /* PistonHeight */
|
||
|
0.1, /* WristPinRadius */
|
||
|
0.5, /* Throw */
|
||
|
0.2, /* CrankPlateThickness */
|
||
|
0.25, /* CrankPinRadius */
|
||
|
0.3, /* CrankJournalRadius */
|
||
|
0.4, /* CrankJournalLength */
|
||
|
1.5, /* ConnectingRodLength */
|
||
|
0.1, /* ConnectingRodThickness */
|
||
|
0, /* CrankList */
|
||
|
0, /* ConnRodList */
|
||
|
0, /* PistonList */
|
||
|
0 /* BlockList */
|
||
|
},
|
||
|
{
|
||
|
"Inline-4",
|
||
|
4, /* Pistons */
|
||
|
4, /* Cranks */
|
||
|
0.0, /* V_Angle */
|
||
|
0.5, /* PistonRadius */
|
||
|
0.6, /* PistonHeight */
|
||
|
0.1, /* WristPinRadius */
|
||
|
0.5, /* Throw */
|
||
|
0.2, /* CrankPlateThickness */
|
||
|
0.25, /* CrankPinRadius */
|
||
|
0.3, /* CrankJournalRadius */
|
||
|
0.4, /* CrankJournalLength */
|
||
|
1.5, /* ConnectingRodLength */
|
||
|
0.1, /* ConnectingRodThickness */
|
||
|
0, /* CrankList */
|
||
|
0, /* ConnRodList */
|
||
|
0, /* PistonList */
|
||
|
0 /* BlockList */
|
||
|
},
|
||
|
{
|
||
|
"Boxer-6",
|
||
|
6, /* Pistons */
|
||
|
3, /* Cranks */
|
||
|
180.0,/* V_Angle */
|
||
|
0.5, /* PistonRadius */
|
||
|
0.6, /* PistonHeight */
|
||
|
0.1, /* WristPinRadius */
|
||
|
0.5, /* Throw */
|
||
|
0.2, /* CrankPlateThickness */
|
||
|
0.25, /* CrankPinRadius */
|
||
|
0.3, /* CrankJournalRadius */
|
||
|
0.4, /* CrankJournalLength */
|
||
|
1.5, /* ConnectingRodLength */
|
||
|
0.1, /* ConnectingRodThickness */
|
||
|
0, /* CrankList */
|
||
|
0, /* ConnRodList */
|
||
|
0, /* PistonList */
|
||
|
0 /* BlockList */
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static int CurEngine = 0;
|
||
|
|
||
|
|
||
|
|
||
|
static void
|
||
|
InitViewInfo(ViewInfo *view)
|
||
|
{
|
||
|
view->Rotating = GL_FALSE;
|
||
|
view->Translating = GL_FALSE;
|
||
|
view->StartX = view->StartY = 0;
|
||
|
view->Distance = 12.0;
|
||
|
view->StartDistance = 0.0;
|
||
|
view->CurQuat[0] = -0.194143;
|
||
|
view->CurQuat[1] = 0.507848;
|
||
|
view->CurQuat[2] = 0.115245;
|
||
|
view->CurQuat[3] = 0.831335;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
InitRenderInfo(RenderInfo *render)
|
||
|
{
|
||
|
render->Mode = LIT;
|
||
|
render->Anim = GL_TRUE;
|
||
|
render->Wireframe = GL_FALSE;
|
||
|
render->Blend = GL_FALSE;
|
||
|
render->Antialias = GL_FALSE;
|
||
|
render->Texture = GL_FALSE;
|
||
|
render->DrawBox = GL_FALSE;
|
||
|
render->ShowInfo = GL_TRUE;
|
||
|
render->ShowBlock = GL_FALSE;
|
||
|
render->UseLists = GL_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Set GL for given rendering mode.
|
||
|
*/
|
||
|
static void
|
||
|
SetRenderState(RenderMode mode)
|
||
|
{
|
||
|
static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 };
|
||
|
static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 };
|
||
|
|
||
|
/* defaults */
|
||
|
glDisable(GL_LIGHTING);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glDisable(GL_BLEND);
|
||
|
glDisable(GL_LINE_SMOOTH);
|
||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||
|
glDisable(GL_TEXTURE_GEN_S);
|
||
|
glDisable(GL_TEXTURE_GEN_T);
|
||
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2);
|
||
|
|
||
|
switch (mode) {
|
||
|
case LIT:
|
||
|
glEnable(GL_LIGHTING);
|
||
|
break;
|
||
|
case WIREFRAME:
|
||
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||
|
glEnable(GL_LINE_SMOOTH);
|
||
|
glEnable(GL_BLEND);
|
||
|
glLineWidth(1.5);
|
||
|
break;
|
||
|
case TEXTURED:
|
||
|
glEnable(GL_LIGHTING);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glEnable(GL_TEXTURE_GEN_S);
|
||
|
glEnable(GL_TEXTURE_GEN_T);
|
||
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4);
|
||
|
break;
|
||
|
default:
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Animate the engine parts.
|
||
|
*/
|
||
|
void idle(void)
|
||
|
{
|
||
|
/* convert degrees per millisecond to RPM: */
|
||
|
const float m = 360.0 / 1000.0 / 60.0;
|
||
|
static GLfloat t;
|
||
|
t+=10;
|
||
|
Theta = ((int) (t * RPM * m)) % 360;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Compute piston's position along its stroke.
|
||
|
*/
|
||
|
static float
|
||
|
PistonStrokePosition(float throwDist, float crankAngle, float connRodLength)
|
||
|
{
|
||
|
float x = throwDist * cos(DEG_TO_RAD(crankAngle));
|
||
|
float y = throwDist * sin(DEG_TO_RAD(crankAngle));
|
||
|
float pos = y + sqrt(connRodLength * connRodLength - x * x);
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Compute position of nth piston along the crankshaft.
|
||
|
*/
|
||
|
static float
|
||
|
PistonShaftPosition(const Engine *eng, int piston)
|
||
|
{
|
||
|
const int i = piston / (eng->Pistons / eng->Cranks);
|
||
|
float z;
|
||
|
assert(piston < eng->Pistons);
|
||
|
z = 1.5 * eng->CrankJournalLength + eng->CrankPlateThickness
|
||
|
+ i * (2.0 * (eng->CrankJournalLength + eng->CrankPlateThickness));
|
||
|
if (eng->Pistons > eng->Cranks) {
|
||
|
if (piston & 1)
|
||
|
z += eng->ConnectingRodThickness;
|
||
|
else
|
||
|
z -= eng->ConnectingRodThickness;
|
||
|
}
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Compute distance between two adjacent pistons
|
||
|
*/
|
||
|
static float
|
||
|
PistonSpacing(const Engine *eng)
|
||
|
{
|
||
|
const int pistonsPerCrank = eng->Pistons / eng->Cranks;
|
||
|
const float z0 = PistonShaftPosition(eng, 0);
|
||
|
const float z1 = PistonShaftPosition(eng, pistonsPerCrank);
|
||
|
return z1 - z0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* (x0, y0) = position of big end on crankshaft
|
||
|
* (x1, y1) = position of small end on piston
|
||
|
*/
|
||
|
static void
|
||
|
ComputeConnectingRodPosition(float throwDist, float crankAngle,
|
||
|
float connRodLength,
|
||
|
float *x0, float *y0, float *x1, float *y1)
|
||
|
{
|
||
|
*x0 = throwDist * cos(DEG_TO_RAD(crankAngle));
|
||
|
*y0 = throwDist * sin(DEG_TO_RAD(crankAngle));
|
||
|
*x1 = 0.0;
|
||
|
*y1 = PistonStrokePosition(throwDist, crankAngle, connRodLength);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Compute total length of the crankshaft.
|
||
|
*/
|
||
|
static float
|
||
|
CrankshaftLength(const Engine *eng)
|
||
|
{
|
||
|
float len = (eng->Cranks * 2 + 1) * eng->CrankJournalLength
|
||
|
+ 2 * eng->Cranks * eng->CrankPlateThickness;
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw a piston.
|
||
|
* Axis of piston = Z axis. Wrist pin is centered on (0, 0, 0).
|
||
|
*/
|
||
|
static void
|
||
|
DrawPiston(const Engine *eng)
|
||
|
{
|
||
|
const int slices = 30, stacks = 4, loops = 4;
|
||
|
const float innerRadius = 0.9 * eng->PistonRadius;
|
||
|
const float innerHeight = eng->PistonHeight - 0.15;
|
||
|
const float wristPinLength = 1.8 * eng->PistonRadius;
|
||
|
|
||
|
assert(Q);
|
||
|
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0, -1.1 * eng->WristPinRadius);
|
||
|
|
||
|
gluQuadricOrientation(Q, GLU_INSIDE);
|
||
|
|
||
|
/* bottom rim */
|
||
|
gluDisk(Q, innerRadius, eng->PistonRadius, slices, 1/*loops*/);
|
||
|
|
||
|
/* inner cylinder */
|
||
|
gluCylinder(Q, innerRadius, innerRadius, innerHeight, slices, stacks);
|
||
|
|
||
|
/* inside top */
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0, innerHeight);
|
||
|
gluDisk(Q, 0, innerRadius, slices, loops);
|
||
|
glPopMatrix();
|
||
|
|
||
|
gluQuadricOrientation(Q, GLU_OUTSIDE);
|
||
|
|
||
|
/* outer cylinder */
|
||
|
gluCylinder(Q, eng->PistonRadius, eng->PistonRadius, eng->PistonHeight,
|
||
|
slices, stacks);
|
||
|
|
||
|
/* top */
|
||
|
glTranslatef(0, 0, eng->PistonHeight);
|
||
|
gluDisk(Q, 0, eng->PistonRadius, slices, loops);
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
/* wrist pin */
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0.5 * wristPinLength, 0.0);
|
||
|
glRotatef(90, 1, 0, 0);
|
||
|
gluCylinder(Q, eng->WristPinRadius, eng->WristPinRadius, wristPinLength,
|
||
|
slices, stacks);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw piston at particular position.
|
||
|
*/
|
||
|
static void
|
||
|
DrawPositionedPiston(const Engine *eng, float crankAngle)
|
||
|
{
|
||
|
const float pos = PistonStrokePosition(eng->Throw, crankAngle,
|
||
|
eng->ConnectingRodLength);
|
||
|
glPushMatrix();
|
||
|
glRotatef(-90, 1, 0, 0);
|
||
|
glTranslatef(0, 0, pos);
|
||
|
if (eng->PistonList)
|
||
|
glCallList(eng->PistonList);
|
||
|
else
|
||
|
DrawPiston(eng);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw connector plate. Used for crankshaft and connecting rods.
|
||
|
*/
|
||
|
static void
|
||
|
DrawConnector(float length, float thickness,
|
||
|
float bigEndRadius, float smallEndRadius)
|
||
|
{
|
||
|
const float bigRadius = 1.2 * bigEndRadius;
|
||
|
const float smallRadius = 1.2 * smallEndRadius;
|
||
|
const float z0 = -0.5 * thickness, z1 = -z0;
|
||
|
GLfloat points[36][2], normals[36][2];
|
||
|
int i;
|
||
|
|
||
|
/* compute vertex locations, normals */
|
||
|
for (i = 0; i < 36; i++) {
|
||
|
const int angle = i * 10;
|
||
|
float x = cos(DEG_TO_RAD(angle));
|
||
|
float y = sin(DEG_TO_RAD(angle));
|
||
|
normals[i][0] = x;
|
||
|
normals[i][1] = y;
|
||
|
if (angle >= 0 && angle <= 180) {
|
||
|
x *= smallRadius;
|
||
|
y = y * smallRadius + length;
|
||
|
}
|
||
|
else {
|
||
|
x *= bigRadius;
|
||
|
y *= bigRadius;
|
||
|
}
|
||
|
points[i][0] = x;
|
||
|
points[i][1] = y;
|
||
|
}
|
||
|
|
||
|
/* front face */
|
||
|
glNormal3f(0, 0, 1);
|
||
|
glBegin(GL_POLYGON);
|
||
|
for (i = 0; i < 36; i++) {
|
||
|
glVertex3f(points[i][0], points[i][1], z1);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* back face */
|
||
|
glNormal3f(0, 0, -1);
|
||
|
glBegin(GL_POLYGON);
|
||
|
for (i = 0; i < 36; i++) {
|
||
|
glVertex3f(points[35-i][0], points[35-i][1], z0);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* edge */
|
||
|
glBegin(GL_QUAD_STRIP);
|
||
|
for (i = 0; i <= 36; i++) {
|
||
|
const int j = i % 36;
|
||
|
glNormal3f(normals[j][0], normals[j][1], 0);
|
||
|
glVertex3f(points[j][0], points[j][1], z1);
|
||
|
glVertex3f(points[j][0], points[j][1], z0);
|
||
|
}
|
||
|
glEnd();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw a crankshaft. Shaft lies along +Z axis, starting at zero.
|
||
|
*/
|
||
|
static void
|
||
|
DrawCrankshaft(const Engine *eng)
|
||
|
{
|
||
|
const int slices = 20, stacks = 2;
|
||
|
const int n = eng->Cranks * 4 + 1;
|
||
|
const float phiStep = 360 / eng->Cranks;
|
||
|
float phi = -90.0;
|
||
|
int i;
|
||
|
float z = 0.0;
|
||
|
|
||
|
for (i = 0; i < n; i++) {
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0, z);
|
||
|
if (i & 1) {
|
||
|
/* draw a crank plate */
|
||
|
glRotatef(phi, 0, 0, 1);
|
||
|
glTranslatef(0, 0, 0.5 * eng->CrankPlateThickness);
|
||
|
DrawConnector(eng->Throw, eng->CrankPlateThickness,
|
||
|
eng->CrankJournalRadius, eng->CrankPinRadius);
|
||
|
z += 0.2;
|
||
|
if (i % 4 == 3)
|
||
|
phi += phiStep;
|
||
|
}
|
||
|
else if (i % 4 == 0) {
|
||
|
/* draw crank journal segment */
|
||
|
gluCylinder(Q, eng->CrankJournalRadius, eng->CrankJournalRadius,
|
||
|
eng->CrankJournalLength, slices, stacks);
|
||
|
z += eng->CrankJournalLength;
|
||
|
}
|
||
|
else if (i % 4 == 2) {
|
||
|
/* draw crank pin segment */
|
||
|
glRotatef(phi, 0, 0, 1);
|
||
|
glTranslatef(0, eng->Throw, 0);
|
||
|
gluCylinder(Q, eng->CrankPinRadius, eng->CrankPinRadius,
|
||
|
eng->CrankJournalLength, slices, stacks);
|
||
|
z += eng->CrankJournalLength;
|
||
|
}
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw crankshaft at a particular rotation.
|
||
|
* \param crankAngle current crankshaft rotation, in radians
|
||
|
*/
|
||
|
static void
|
||
|
DrawPositionedCrankshaft(const Engine *eng, float crankAngle)
|
||
|
{
|
||
|
glPushMatrix();
|
||
|
glRotatef(crankAngle, 0, 0, 1);
|
||
|
if (eng->CrankList)
|
||
|
glCallList(eng->CrankList);
|
||
|
else
|
||
|
DrawCrankshaft(eng);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw a connecting rod at particular position.
|
||
|
* \param eng description of connecting rod to draw
|
||
|
* \param crankAngle current crankshaft rotation, in radians
|
||
|
*/
|
||
|
static void
|
||
|
DrawPositionedConnectingRod(const Engine *eng, float crankAngle)
|
||
|
{
|
||
|
float x0, y0, x1, y1;
|
||
|
float d, phi;
|
||
|
|
||
|
ComputeConnectingRodPosition(eng->Throw, crankAngle,
|
||
|
eng->ConnectingRodLength,
|
||
|
&x0, &y0, &x1, &y1);
|
||
|
d = sqrt(eng->ConnectingRodLength * eng->ConnectingRodLength - x0 * x0);
|
||
|
phi = atan(x0 / d) * 180.0 / M_PI;
|
||
|
|
||
|
glPushMatrix();
|
||
|
glTranslatef(x0, y0, 0);
|
||
|
glRotatef(phi, 0, 0, 1);
|
||
|
if (eng->ConnRodList)
|
||
|
glCallList(eng->ConnRodList);
|
||
|
else
|
||
|
DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
|
||
|
eng->CrankPinRadius, eng->WristPinRadius);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw a square with a hole in middle.
|
||
|
*/
|
||
|
static void
|
||
|
SquareWithHole(float squareSize, float holeRadius)
|
||
|
{
|
||
|
int i;
|
||
|
glBegin(GL_QUAD_STRIP);
|
||
|
glNormal3f(0, 0, 1);
|
||
|
for (i = 0; i <= 360; i += 5) {
|
||
|
const float x1 = holeRadius * cos(DEG_TO_RAD(i));
|
||
|
const float y1 = holeRadius * sin(DEG_TO_RAD(i));
|
||
|
float x2 = 0.0F, y2 = 0.0F;
|
||
|
if (i > 315 || i <= 45) {
|
||
|
x2 = squareSize;
|
||
|
y2 = squareSize * tan(DEG_TO_RAD(i));
|
||
|
}
|
||
|
else if (i > 45 && i <= 135) {
|
||
|
x2 = -squareSize * tan(DEG_TO_RAD(i - 90));
|
||
|
y2 = squareSize;
|
||
|
}
|
||
|
else if (i > 135 && i <= 225) {
|
||
|
x2 = -squareSize;
|
||
|
y2 = -squareSize * tan(DEG_TO_RAD(i-180));
|
||
|
}
|
||
|
else if (i > 225 && i <= 315) {
|
||
|
x2 = squareSize * tan(DEG_TO_RAD(i - 270));
|
||
|
y2 = -squareSize;
|
||
|
}
|
||
|
glVertex2f(x1, y1); /* inner circle */
|
||
|
glVertex2f(x2, y2); /* outer square */
|
||
|
}
|
||
|
glEnd();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw block with hole through middle.
|
||
|
* Hole is centered on Z axis.
|
||
|
* Bottom of block is at z=0, top of block is at z = blockHeight.
|
||
|
* index is in [0, count - 1] to determine which block faces are drawn.
|
||
|
*/
|
||
|
static void
|
||
|
DrawBlockWithHole(float blockSize, float blockHeight, float holeRadius,
|
||
|
int index, int count)
|
||
|
{
|
||
|
const int slices = 30, stacks = 4;
|
||
|
const float x = blockSize;
|
||
|
const float y = blockSize;
|
||
|
const float z0 = 0;
|
||
|
const float z1 = blockHeight;
|
||
|
|
||
|
assert(index < count);
|
||
|
assert(Q);
|
||
|
gluQuadricOrientation(Q, GLU_INSIDE);
|
||
|
|
||
|
glBegin(GL_QUADS);
|
||
|
/* +X face */
|
||
|
glNormal3f(1, 0, 0);
|
||
|
glVertex3f( x, -y, z0);
|
||
|
glVertex3f( x, y, z0);
|
||
|
glVertex3f( x, y, z1);
|
||
|
glVertex3f( x, -y, z1);
|
||
|
/* -X face */
|
||
|
glNormal3f(-1, 0, 0);
|
||
|
glVertex3f(-x, -y, z1);
|
||
|
glVertex3f(-x, y, z1);
|
||
|
glVertex3f(-x, y, z0);
|
||
|
glVertex3f(-x, -y, z0);
|
||
|
if (index == 0) {
|
||
|
/* +Y face */
|
||
|
glNormal3f(0, 1, 0);
|
||
|
glVertex3f(-x, y, z1);
|
||
|
glVertex3f( x, y, z1);
|
||
|
glVertex3f( x, y, z0);
|
||
|
glVertex3f(-x, y, z0);
|
||
|
}
|
||
|
if (index == count - 1) {
|
||
|
/* -Y face */
|
||
|
glNormal3f(0, -1, 0);
|
||
|
glVertex3f(-x, -y, z0);
|
||
|
glVertex3f( x, -y, z0);
|
||
|
glVertex3f( x, -y, z1);
|
||
|
glVertex3f(-x, -y, z1);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* cylinder / hole */
|
||
|
gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks);
|
||
|
|
||
|
/* face at z0 */
|
||
|
glPushMatrix();
|
||
|
glRotatef(180, 1, 0, 0);
|
||
|
SquareWithHole(blockSize, holeRadius);
|
||
|
glPopMatrix();
|
||
|
|
||
|
/* face at z1 */
|
||
|
glTranslatef(0, 0, z1);
|
||
|
SquareWithHole(blockSize, holeRadius);
|
||
|
|
||
|
gluQuadricOrientation(Q, GLU_OUTSIDE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw the engine block.
|
||
|
*/
|
||
|
static void
|
||
|
DrawEngineBlock(const Engine *eng)
|
||
|
{
|
||
|
const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight;
|
||
|
const float cylRadius = 1.01 * eng->PistonRadius;
|
||
|
const float blockSize = 0.5 * PistonSpacing(eng);
|
||
|
const int pistonsPerCrank = eng->Pistons / eng->Cranks;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < eng->Pistons; i++) {
|
||
|
const float z = PistonShaftPosition(eng, i);
|
||
|
const int crank = i / pistonsPerCrank;
|
||
|
int k;
|
||
|
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0, z);
|
||
|
|
||
|
/* additional rotation for kth piston per crank */
|
||
|
k = i % pistonsPerCrank;
|
||
|
glRotatef(k * -eng->V_Angle, 0, 0, 1);
|
||
|
|
||
|
/* the block */
|
||
|
glRotatef(-90, 1, 0, 0);
|
||
|
glTranslatef(0, 0, eng->Throw * 2);
|
||
|
DrawBlockWithHole(blockSize, blockHeight, cylRadius,
|
||
|
crank, eng->Cranks);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Generate display lists for engine parts.
|
||
|
*/
|
||
|
static void
|
||
|
GenerateDisplayLists(Engine *eng)
|
||
|
{
|
||
|
eng->CrankList = glGenLists(1);
|
||
|
glNewList(eng->CrankList, GL_COMPILE);
|
||
|
DrawCrankshaft(eng);
|
||
|
glEndList();
|
||
|
|
||
|
eng->ConnRodList = glGenLists(1);
|
||
|
glNewList(eng->ConnRodList, GL_COMPILE);
|
||
|
DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
|
||
|
eng->CrankPinRadius, eng->WristPinRadius);
|
||
|
glEndList();
|
||
|
|
||
|
eng->PistonList = glGenLists(1);
|
||
|
glNewList(eng->PistonList, GL_COMPILE);
|
||
|
DrawPiston(eng);
|
||
|
glEndList();
|
||
|
|
||
|
eng->BlockList = glGenLists(1);
|
||
|
glNewList(eng->BlockList, GL_COMPILE);
|
||
|
DrawEngineBlock(eng);
|
||
|
glEndList();
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Free engine display lists (render with immediate mode).
|
||
|
*/
|
||
|
static void
|
||
|
FreeDisplayLists(Engine *eng)
|
||
|
{
|
||
|
glDeleteLists(eng->CrankList, 1);
|
||
|
eng->CrankList = 0;
|
||
|
glDeleteLists(eng->ConnRodList, 1);
|
||
|
eng->ConnRodList = 0;
|
||
|
glDeleteLists(eng->PistonList, 1);
|
||
|
eng->PistonList = 0;
|
||
|
glDeleteLists(eng->BlockList, 1);
|
||
|
eng->BlockList = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Draw complete engine.
|
||
|
* \param eng description of engine to draw
|
||
|
* \param crankAngle current crankshaft angle, in radians
|
||
|
*/
|
||
|
static void
|
||
|
DrawEngine(const Engine *eng, float crankAngle)
|
||
|
{
|
||
|
const float crankDelta = 360.0 / eng->Cranks;
|
||
|
const float crankLen = CrankshaftLength(eng);
|
||
|
const int pistonsPerCrank = eng->Pistons / eng->Cranks;
|
||
|
int i;
|
||
|
|
||
|
glPushMatrix();
|
||
|
glRotatef(eng->V_Angle * 0.5, 0, 0, 1);
|
||
|
glTranslatef(0, 0, -0.5 * crankLen);
|
||
|
|
||
|
/* crankshaft */
|
||
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, CrankshaftColor);
|
||
|
glColor4fv(CrankshaftColor);
|
||
|
DrawPositionedCrankshaft(eng, crankAngle);
|
||
|
|
||
|
for (i = 0; i < eng->Pistons; i++) {
|
||
|
const float z = PistonShaftPosition(eng, i);
|
||
|
const int crank = i / pistonsPerCrank;
|
||
|
float rot = crankAngle + crank * crankDelta;
|
||
|
int k;
|
||
|
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, 0, z);
|
||
|
|
||
|
/* additional rotation for kth piston per crank */
|
||
|
k = i % pistonsPerCrank;
|
||
|
glRotatef(k * -eng->V_Angle, 0, 0, 1);
|
||
|
rot += k * eng->V_Angle;
|
||
|
|
||
|
/* piston */
|
||
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, PistonColor);
|
||
|
glColor4fv(PistonColor);
|
||
|
DrawPositionedPiston(eng, rot);
|
||
|
|
||
|
/* connecting rod */
|
||
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ConnRodColor);
|
||
|
glColor4fv(ConnRodColor);
|
||
|
DrawPositionedConnectingRod(eng, rot);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
if (Render.ShowBlock) {
|
||
|
const GLboolean blend = glIsEnabled(GL_BLEND);
|
||
|
|
||
|
glDepthMask(GL_FALSE);
|
||
|
if (!blend) {
|
||
|
glEnable(GL_BLEND);
|
||
|
}
|
||
|
glEnable(GL_CULL_FACE);
|
||
|
|
||
|
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, BlockColor);
|
||
|
glColor4fv(BlockColor);
|
||
|
if (eng->CrankList)
|
||
|
glCallList(eng->BlockList);
|
||
|
else
|
||
|
DrawEngineBlock(eng);
|
||
|
|
||
|
glDisable(GL_CULL_FACE);
|
||
|
glDepthMask(GL_TRUE);
|
||
|
if (!blend) {
|
||
|
glDisable(GL_BLEND);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
DrawBox(void)
|
||
|
{
|
||
|
const float xmin = -3.0, xmax = 3.0;
|
||
|
const float ymin = -1.0, ymax = 3.0;
|
||
|
const float zmin = -4.0, zmax = 4.0;
|
||
|
const float step = 0.5;
|
||
|
const float d = 0.01;
|
||
|
float x, y, z;
|
||
|
GLboolean lit = glIsEnabled(GL_LIGHTING);
|
||
|
GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
|
||
|
|
||
|
glDisable(GL_LIGHTING);
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glLineWidth(1.0);
|
||
|
|
||
|
glColor3f(1, 1, 1);
|
||
|
|
||
|
/* Z min */
|
||
|
glBegin(GL_LINES);
|
||
|
for (x = xmin; x <= xmax; x += step) {
|
||
|
glVertex3f(x, ymin, zmin);
|
||
|
glVertex3f(x, ymax, zmin);
|
||
|
}
|
||
|
glEnd();
|
||
|
glBegin(GL_LINES);
|
||
|
for (y = ymin; y <= ymax; y += step) {
|
||
|
glVertex3f(xmin, y, zmin);
|
||
|
glVertex3f(xmax, y, zmin);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* Y min */
|
||
|
glBegin(GL_LINES);
|
||
|
for (x = xmin; x <= xmax; x += step) {
|
||
|
glVertex3f(x, ymin, zmin);
|
||
|
glVertex3f(x, ymin, zmax);
|
||
|
}
|
||
|
glEnd();
|
||
|
glBegin(GL_LINES);
|
||
|
for (z = zmin; z <= zmax; z += step) {
|
||
|
glVertex3f(xmin, ymin, z);
|
||
|
glVertex3f(xmax, ymin, z);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* X min */
|
||
|
glBegin(GL_LINES);
|
||
|
for (y = ymin; y <= ymax; y += step) {
|
||
|
glVertex3f(xmin, y, zmin);
|
||
|
glVertex3f(xmin, y, zmax);
|
||
|
}
|
||
|
glEnd();
|
||
|
glBegin(GL_LINES);
|
||
|
for (z = zmin; z <= zmax; z += step) {
|
||
|
glVertex3f(xmin, ymin, z);
|
||
|
glVertex3f(xmin, ymax, z);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
glColor3f(0.4, 0.4, 0.6);
|
||
|
glBegin(GL_QUADS);
|
||
|
/* xmin */
|
||
|
glVertex3f(xmin-d, ymin, zmin);
|
||
|
glVertex3f(xmin-d, ymax, zmin);
|
||
|
glVertex3f(xmin-d, ymax, zmax);
|
||
|
glVertex3f(xmin-d, ymin, zmax);
|
||
|
/* ymin */
|
||
|
glVertex3f(xmin, ymin-d, zmin);
|
||
|
glVertex3f(xmax, ymin-d, zmin);
|
||
|
glVertex3f(xmax, ymin-d, zmax);
|
||
|
glVertex3f(xmin, ymin-d, zmax);
|
||
|
/* zmin */
|
||
|
glVertex3f(xmin, ymin, zmin-d);
|
||
|
glVertex3f(xmax, ymin, zmin-d);
|
||
|
glVertex3f(xmax, ymax, zmin-d);
|
||
|
glVertex3f(xmin, ymax, zmin-d);
|
||
|
glEnd();
|
||
|
|
||
|
if (lit)
|
||
|
glEnable(GL_LIGHTING);
|
||
|
if (tex)
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
static void
|
||
|
PrintString(const char *s)
|
||
|
{
|
||
|
while (*s) {
|
||
|
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
|
||
|
s++;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
void draw(void)
|
||
|
{
|
||
|
int fps;
|
||
|
GLfloat rot[4][4];
|
||
|
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
|
||
|
glPushMatrix();
|
||
|
|
||
|
glTranslatef(0.0, 0.0, -View.Distance);
|
||
|
build_rotmatrix(rot, View.CurQuat);
|
||
|
glMultMatrixf(&rot[0][0]);
|
||
|
|
||
|
glPushMatrix();
|
||
|
glTranslatef(0, -0.75, 0);
|
||
|
if (Render.DrawBox)
|
||
|
DrawBox();
|
||
|
DrawEngine(Engines + CurEngine, Theta);
|
||
|
glPopMatrix();
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Handle window resize.
|
||
|
*/
|
||
|
void reshape(int width, int height)
|
||
|
{
|
||
|
float ar = (float) width / height;
|
||
|
float s = 0.5;
|
||
|
glViewport(0, 0, width, height);
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
glFrustum(-ar * s, ar * s, -s, s, 2.0, 50.0);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glLoadIdentity();
|
||
|
WinWidth = width;
|
||
|
WinHeight = height;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
/**
|
||
|
* Handle mouse button.
|
||
|
*/
|
||
|
static void
|
||
|
Mouse(int button, int state, int x, int y)
|
||
|
{
|
||
|
if (button == GLUT_LEFT_BUTTON) {
|
||
|
if (state == GLUT_DOWN) {
|
||
|
View.StartX = x;
|
||
|
View.StartY = y;
|
||
|
View.Rotating = GL_TRUE;
|
||
|
}
|
||
|
else if (state == GLUT_UP) {
|
||
|
View.Rotating = GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
else if (button == GLUT_MIDDLE_BUTTON) {
|
||
|
if (state == GLUT_DOWN) {
|
||
|
View.StartX = x;
|
||
|
View.StartY = y;
|
||
|
View.StartDistance = View.Distance;
|
||
|
View.Translating = GL_TRUE;
|
||
|
}
|
||
|
else if (state == GLUT_UP) {
|
||
|
View.Translating = GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Handle mouse motion
|
||
|
*/
|
||
|
static void
|
||
|
Motion(int x, int y)
|
||
|
{
|
||
|
int i;
|
||
|
if (View.Rotating) {
|
||
|
float x0 = (2.0 * View.StartX - WinWidth) / WinWidth;
|
||
|
float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight;
|
||
|
float x1 = (2.0 * x - WinWidth) / WinWidth;
|
||
|
float y1 = (WinHeight - 2.0 * y) / WinHeight;
|
||
|
float q[4];
|
||
|
|
||
|
trackball(q, x0, y0, x1, y1);
|
||
|
View.StartX = x;
|
||
|
View.StartY = y;
|
||
|
for (i = 0; i < 1; i++)
|
||
|
add_quats(q, View.CurQuat, View.CurQuat);
|
||
|
}
|
||
|
else if (View.Translating) {
|
||
|
float dz = 0.01 * (y - View.StartY);
|
||
|
View.Distance = View.StartDistance + dz;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
** Menu Callbacks
|
||
|
**/
|
||
|
|
||
|
static void
|
||
|
OptChangeEngine(void)
|
||
|
{
|
||
|
CurEngine = (CurEngine + 1) % NUM_ENGINES;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptRenderMode(void)
|
||
|
{
|
||
|
Render.Mode++;
|
||
|
if (Render.Mode > TEXTURED)
|
||
|
Render.Mode = 0;
|
||
|
SetRenderState(Render.Mode);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptDisplayLists(void)
|
||
|
{
|
||
|
int i;
|
||
|
Render.UseLists = !Render.UseLists;
|
||
|
if (Render.UseLists) {
|
||
|
for (i = 0; i < NUM_ENGINES; i++) {
|
||
|
GenerateDisplayLists(Engines + i);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
for (i = 0; i < NUM_ENGINES; i++) {
|
||
|
FreeDisplayLists(Engines + i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptShowBlock(void)
|
||
|
{
|
||
|
Render.ShowBlock = !Render.ShowBlock;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptShowInfo(void)
|
||
|
{
|
||
|
Render.ShowInfo = !Render.ShowInfo;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptShowBox(void)
|
||
|
{
|
||
|
Render.DrawBox = !Render.DrawBox;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
OptRotate(void)
|
||
|
{
|
||
|
Theta += 5.0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Define menu entries (w/ keyboard shortcuts)
|
||
|
*/
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
const char *Text;
|
||
|
const char Key;
|
||
|
void (*Function)(void);
|
||
|
} MenuInfo;
|
||
|
|
||
|
static const MenuInfo MenuItems[] = {
|
||
|
{ "Change Engine", 'e', OptChangeEngine },
|
||
|
{ "Rendering Style", 'm', OptRenderMode },
|
||
|
{ "Display Lists", 'd', OptDisplayLists },
|
||
|
{ "Show Block", 98, OptShowBlock }, /* b */
|
||
|
{ "Show Box", 'x', OptShowBox },
|
||
|
{ NULL, 'r', OptRotate },
|
||
|
{ NULL, 0, NULL }
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Handle keyboard event.
|
||
|
*/
|
||
|
void Key(unsigned char key, int x, int y)
|
||
|
{
|
||
|
int i;
|
||
|
(void) x; (void) y;
|
||
|
|
||
|
for (i = 0; MenuItems[i].Key; i++)
|
||
|
{
|
||
|
if (MenuItems[i].Key == key)
|
||
|
{
|
||
|
MenuItems[i].Function();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void LoadTexture(void)
|
||
|
{
|
||
|
GLboolean convolve = GL_FALSE;
|
||
|
|
||
|
glGenTextures(1, &TextureObj);
|
||
|
glBindTexture(GL_TEXTURE_2D, TextureObj);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
||
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
||
|
|
||
|
if (convolve) {
|
||
|
#define FILTER_SIZE 7
|
||
|
/* use convolution to blur the texture to simulate a dull finish
|
||
|
* on the object.
|
||
|
*/
|
||
|
GLubyte *img;
|
||
|
GLenum format;
|
||
|
GLint w, h;
|
||
|
GLfloat filter[FILTER_SIZE][FILTER_SIZE][4];
|
||
|
|
||
|
for (h = 0; h < FILTER_SIZE; h++) {
|
||
|
for (w = 0; w < FILTER_SIZE; w++) {
|
||
|
const GLfloat k = 1.0 / (FILTER_SIZE * FILTER_SIZE);
|
||
|
filter[h][w][0] = k;
|
||
|
filter[h][w][1] = k;
|
||
|
filter[h][w][2] = k;
|
||
|
filter[h][w][3] = k;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
glEnable(GL_CONVOLUTION_2D);
|
||
|
glConvolutionParameteri(GL_CONVOLUTION_2D,
|
||
|
GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER);
|
||
|
glConvolutionFilter2D(GL_CONVOLUTION_2D, GL_RGBA,
|
||
|
FILTER_SIZE, FILTER_SIZE,
|
||
|
GL_RGBA, GL_FLOAT, filter);
|
||
|
|
||
|
img = LoadRGBImage(TEXTURE_FILE, &w, &h, &format);
|
||
|
if (!img) {
|
||
|
printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
|
||
|
format, GL_UNSIGNED_BYTE, img);
|
||
|
free(img);
|
||
|
}
|
||
|
else {
|
||
|
if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
|
||
|
printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void init(void)
|
||
|
{
|
||
|
const GLfloat lightColor[4] = { 0.7, 0.7, 0.7, 1.0 };
|
||
|
const GLfloat specular[4] = { 0.8, 0.8, 0.8, 1.0 };
|
||
|
const GLfloat backColor[4] = { 1, 1, 0, 0 };
|
||
|
|
||
|
Q = gluNewQuadric();
|
||
|
gluQuadricNormals(Q, GLU_SMOOTH);
|
||
|
|
||
|
LoadTexture();
|
||
|
|
||
|
glClearColor(0.3, 0.3, 0.3, 0.0);
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
glEnable(GL_LIGHTING);
|
||
|
glEnable(GL_LIGHT0);
|
||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
|
||
|
glMaterialf(GL_FRONT, GL_SHININESS, 40);
|
||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
|
||
|
glEnable(GL_NORMALIZE);
|
||
|
|
||
|
glMaterialfv(GL_BACK, GL_DIFFUSE, backColor);
|
||
|
#if 0
|
||
|
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
|
||
|
#endif
|
||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
|
|
||
|
InitViewInfo(&View);
|
||
|
InitRenderInfo(&Render);
|
||
|
}
|
||
|
|
||
|
int atexit(void (*func)(void))
|
||
|
{
|
||
|
return 0;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
#define GL_NO_ERROR 0x0
|
||
|
#define GL_INVALID_ENUM 0x0500
|
||
|
#define GL_INVALID_VALUE 0x0501
|
||
|
#define GL_INVALID_OPERATION 0x0502
|
||
|
#define GL_STACK_OVERFLOW 0x0503
|
||
|
#define GL_STACK_UNDERFLOW 0x0504
|
||
|
#define GL_OUT_OF_MEMORY 0x0505
|
||
|
*/
|
||
|
|
||
|
|
||
|
|