home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Exec 5
/
CD_Magazyn_EXEC_nr_5.iso
/
eXec
/
MiniGL
/
gears.c
next >
Wrap
C/C++ Source or Header
|
2000-11-30
|
18KB
|
806 lines
/*
W komentarzach jest straszny baîagan: czëôê pochodzi z oryginaîu (po
angielsku), pozostaîe - dotyczâce róûnic miëdzy MGL i GLUT - sâ moje
(po polsku).
*/
#include <stdlib.h>
#include <string.h>
#ifdef __USE_GLUT__
#include <gl/glut.h>
#else
#include <mgl/gl.h>
#endif
#include <math.h>
/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265
#endif
#include <stdio.h>
/* For portability... */
#undef fcos
#undef fsin
#undef fsqrt
#define fcos cos
#define fsin sin
#define fsqrt sqrt
static double d_near = 1.0;
static double d_far = 2000;
int show = 1;
typedef struct {
float rad, wid;
} Profile;
int circle_subdiv;
#define MIN_SUBDIV 30
GLboolean bEnvMap = GL_TRUE;
void flat_face( float ir, float or, float wd );
void draw_inside( float w1, float w2, float rad );
void draw_outside( float w1, float w2, float rad );
void tooth_side( int nt, float ir, float or, float tp, float tip, float wd );
#ifndef __USE_GLUT__
/* MiniGL wymaga doîâczenia do kaûdego programu funkcji 'kprintf'.
Powinna ona wypisywaê tekst do portu szeregowego (lub Sushi, jeûeli
jest uruchomiony). W tym programiku jest to zupelnie niepotrzebne. */
int kprintf( char *format, ... )
{
return 1;
}
#endif
GLubyte *LoadPPM( char *name, GLint *w, GLint *h )
{
int i;
unsigned long x, y;
FILE *f;
GLubyte *where;
f = fopen( name, "r" );
if( !f )
{
*w = 0; *h=0;
return NULL;
}
#ifndef __STORM__
i = fscanf( f, "P6\n%ld %ld\n255\n",&x, &y );
#else
i = fscanf( f, "P6\n%ld\n%ld\n255\n", &x, &y );
#endif
if( i!= 2 )
{
printf( "Error scanning PPM header\n" );
fclose( f );
*w = 0; *h = 0;
return NULL;
}
*w = x;
*h = y;
where = malloc( x * y * 4 );
if( !where )
{
printf( "Error out of Memory\n" );
fclose( f );
*w = 0; *h = 0;
return NULL;
}
i = fread( where, 1, x * y * 3, f );
fclose(f);
if( i != x * y * 3 )
{
printf( "Error while reading file\n" );
free( where );
*w = 0; *h = 0;
return NULL;
}
return where;
}
GLboolean TexInit( char *name )
{
GLubyte *tmap;
GLint x,y;
/* Te dwie funkcje nie sâ konieczne w przypadku uûywania GLUT,
bo wartoôci domyôlne (UN)PACK_ALIGNMENT sâ ok. Jeûeli nie
bëdzie ich w programie uûywajâcym MiniGL to moûemy zamiast
tekstury dostaê ômieci. */
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
if( !name )
{
tmap = LoadPPM( "chrome.ppm",&x, &y );
}
else
{
tmap = LoadPPM( name, &x, &y );
}
if( !tmap )
return GL_FALSE;
glBindTexture( GL_TEXTURE_2D, 1 );
glTexImage2D( GL_TEXTURE_2D,
0,
3,
x, y,
0,
GL_RGB,
GL_UNSIGNED_BYTE, tmap );
free(tmap);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glEnable( GL_TEXTURE_2D );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
return GL_TRUE;
}
void gear( int nt, float wd, float ir, float or, float tp, float tip, int ns, Profile *ip )
{
/**
* nt - number of teeth
* wd - width of gear at teeth
* ir - inside radius absolute scale
* or - radius at outside of wheel (tip of tooth) ratio of ir
* tp - ratio of tooth in slice of circle (0..1] (1 = teeth are touching at base)
* tip - ratio of tip of tooth (0..tp] (cant be wider that base of tooth)
* ns - number of elements in wheel width profile
* *ip - list of float pairs {start radius, width, ...} (width is ratio to wd)
*
*/
/* gear lying on xy plane, z for width. all normals calulated (normalized) */
float prev;
int k, t;
/* estimat # times to divide circle */
if( nt <= 0 )
circle_subdiv = MIN_SUBDIV;
else
{
/* lowest multiple of number of teeth */
circle_subdiv = nt;
while( circle_subdiv < MIN_SUBDIV )
circle_subdiv += nt;
}
/* --- draw wheel face --- */
/* draw horzontal, vertical faces for each section. if first
section radius not zero, use wd for 0.. first if ns == 0
use wd for whole face. last width used to edge. */
if( ns <= 0 )
{
flat_face( 0.0, ir, wd );
}
else
{
/* draw first flat_face, then continue in loop */
if( ip[0].rad > 0.0 )
{
flat_face( 0.0, ip[0].rad * ir, wd );
prev = wd;
t = 0;
}
else
{
flat_face( 0.0, ip[1].rad * ir, ip[0].wid * wd );
prev = ip[0].wid;
t = 1;
}
for( k = t ; k < ns ; k++ )
{
if( prev < ip[k].wid )
{
draw_inside( prev * wd, ip[k].wid * wd, ip[k].rad * ir );
}
else
{
draw_outside( prev * wd, ip[k].wid * wd, ip[k].rad * ir );
}
prev = ip[k].wid;
/* - draw to edge of wheel, add final face if needed - */
if( k == ns - 1 )
{
flat_face( ip[k].rad * ir, ir, ip[k].wid * wd );
/* now draw side to match tooth rim */
if( ip[k].wid < 1.0 )
{
draw_inside( ip[k].wid * wd, wd, ir );
}
else
{
draw_outside( ip[k].wid * wd, wd, ir );
}
}
else
{
flat_face( ip[k].rad * ir, ip[k + 1].rad * ir, ip[k].wid * wd );
}
}
}
/* --- tooth side faces --- */
tooth_side( nt, ir, or, tp, tip, wd );
/* --- tooth hill surface --- */
}
void tooth_side( int nt, float ir, float or, float tp, float tip, float wd )
{
float i;
float end = 2.0 * M_PI / nt;
float x[6], y[6];
float s[3], c[3];
or = or * ir; /* or is really a ratio of ir */
for( i = 0 ; i < 2.0 * M_PI - end / 4.0 ; i += end )
{
c[0] = fcos( i );
s[0] = fsin( i );
c[1] = fcos( i + end * (0.5 - tip / 2) );
s[1] = fsin( i + end * (0.5 - tip / 2) );
c[2] = fcos( i + end * (0.5 + tp / 2) );
s[2] = fsin( i + end * (0.5 + tp / 2) );
x[0] = ir * c[0];
y[0] = ir * s[0];
x[5] = ir * fcos( i + end );
y[5] = ir * fsin( i + end );
/* ---treat veritices 1,4 special to match strait edge of face */
x[1] = x[0] + (x[5] - x[0]) * (0.5 - tp / 2);
y[1] = y[0] + (y[5] - y[0]) * (0.5 - tp / 2);
x[4] = x[0] + (x[5] - x[0]) * (0.5 + tp / 2);
y[4] = y[0] + (y[5] - y[0]) * (0.5 + tp / 2);
x[2] = or * fcos( i + end * (0.5 - tip / 2) );
y[2] = or * fsin( i + end * (0.5 - tip / 2) );
x[3] = or * fcos( i + end * (0.5 + tip / 2) );
y[3] = or * fsin( i + end * (0.5 + tip / 2) );
/* draw face trapezoids as 2 tmesh */
glNormal3f( 0.0, 0.0, 1.0 );
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[2], y[2], wd / 2 );
glVertex3f( x[1], y[1], wd / 2 );
glVertex3f( x[3], y[3], wd / 2 );
glVertex3f( x[4], y[4], wd / 2 );
glEnd();
glNormal3f( 0.0, 0.0, -1.0 );
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[2], y[2], -wd / 2 );
glVertex3f( x[1], y[1], -wd / 2 );
glVertex3f( x[3], y[3], -wd / 2 );
glVertex3f( x[4], y[4], -wd / 2 );
glEnd();
/* draw inside rim pieces */
glNormal3f( c[0], s[0], 0.0 );
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[0], y[0], -wd / 2 );
glVertex3f( x[1], y[1], -wd / 2 );
glVertex3f( x[0], y[0], wd / 2 );
glVertex3f( x[1], y[1], wd / 2 );
glEnd();
/* draw up hill side */
{
float a, b, n;
/* calculate normal of face */
a = x[2] - x[1];
b = y[2] - y[1];
n = 1.0 / fsqrt( a * a + b * b );
a = a * n;
b = b * n;
glNormal3f( b, -a, 0.0 );
}
glBegin( GL_TRIANGLE_STRIP);
glVertex3f( x[1], y[1], -wd / 2 );
glVertex3f( x[2], y[2], -wd / 2 );
glVertex3f( x[1], y[1], wd / 2 );
glVertex3f( x[2], y[2], wd / 2 );
glEnd();
/* draw top of hill */
glNormal3f( c[1], s[1], 0.0 );
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[2], y[2], -wd / 2 );
glVertex3f( x[3], y[3], -wd / 2 );
glVertex3f( x[2], y[2], wd / 2 );
glVertex3f( x[3], y[3], wd / 2 );
glEnd();
/* draw down hill side */
{
float a, b, c;
/* calculate normal of face */
a = x[4] - x[3];
b = y[4] - y[3];
c = 1.0 / fsqrt( a * a + b * b );
a = a * c;
b = b * c;
glNormal3f( b, -a, 0.0 );
}
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[3], y[3], -wd / 2 );
glVertex3f( x[4], y[4], -wd / 2 );
glVertex3f( x[3], y[3], wd / 2 );
glVertex3f( x[4], y[4], wd / 2 );
glEnd();
/* inside rim part */
glNormal3f( c[2], s[2], 0.0 );
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( x[4], y[4], -wd / 2 );
glVertex3f( x[5], y[5], -wd / 2 );
glVertex3f( x[4], y[4], wd / 2 );
glVertex3f( x[5], y[5], wd / 2 );
glEnd();
}
}
void flat_face( float ir, float or, float wd )
{
int i;
float c, s;
float w;
/* draw each face (top & bottom ) * */
if( wd == 0.0 )
return;
for( w = wd / 2 ; w > -wd ; w -= wd )
{
if(w > 0.0)
glNormal3f( 0.0, 0.0, 1.0 );
else
glNormal3f( 0.0, 0.0, -1.0 );
if( ir == 0.0 )
{
/* draw as t-fan */
glBegin( GL_TRIANGLE_FAN );
glVertex3f( 0.0, 0.0, w ); /* center */
glVertex3f( or, 0.0, w );
for( i = 1 ; i < circle_subdiv ; i++ )
{
glVertex3f( fcos( 2.0 * M_PI * i / (float)circle_subdiv ) * or,
fsin( 2.0 * M_PI * i / (float)circle_subdiv ) * or,
w );
}
glVertex3f( or, 0.0, w );
glEnd();
}
else
{
/* draw as tmesh */
glBegin( GL_TRIANGLE_STRIP );
glVertex3f( or, 0.0, w );
glVertex3f( ir, 0.0, w );
for( i = 1 ; i < circle_subdiv ; i++)
{
s = fsin( 2.0 * M_PI * i / (float)circle_subdiv );
c = fcos( 2.0 * M_PI * i / (float)circle_subdiv );
glVertex3f( c * or, s * or, w );
glVertex3f( c * ir, s * ir, w );
}
glVertex3f( or, 0.0, w );
glVertex3f( ir, 0.0, w );
glEnd();
}
}
}
void draw_inside( float w1, float w2, float rad )
{
int i, j;
float c, s;
if( w1 == w2 )
return;
w1 = w1 / 2;
w2 = w2 / 2;
for( j = 0 ; j < 2 ; j++ )
{
if( j == 1 )
{
w1 = -w1;
w2 = -w2;
}
glBegin( GL_TRIANGLE_STRIP );
glNormal3f( -1.0, 0.0, 0.0 );
glVertex3f( rad, 0.0, w1 );
glVertex3f( rad, 0.0, w2 );
for( i = 1 ; i < circle_subdiv ; i++ )
{
c = fcos( 2.0 * M_PI * i / circle_subdiv );
s = fsin( 2.0 * M_PI * i / circle_subdiv );
glNormal3f( -c, -s, 0.0 );
glVertex3f( c * rad, s * rad, w1 );
glVertex3f( c * rad, s * rad, w2 );
}
glNormal3f( -1.0, 0.0, 0.0 );
glVertex3f( rad, 0.0, w1 );
glVertex3f( rad, 0.0, w2 );
glEnd();
}
}
void draw_outside( float w1, float w2, float rad )
{
int i, j;
float c, s;
if( w1 == w2 )
return;
w1 = w1 / 2;
w2 = w2 / 2;
for( j = 0 ; j < 2 ; j++ )
{
if( j == 1 )
{
w1 = -w1;
w2 = -w2;
}
glBegin( GL_TRIANGLE_STRIP );
glNormal3f( 1.0, 0.0, 0.0 );
glVertex3f( rad, 0.0, w1 );
glVertex3f( rad, 0.0, w2 );
for( i = 1 ; i < circle_subdiv ; i++ )
{
c = fcos( 2.0 * M_PI * i / (float)circle_subdiv );
s = fsin( 2.0 * M_PI * i / (float)circle_subdiv );
glNormal3f( c, s, 0.0 );
glVertex3f( c * rad, s * rad, w1 );
glVertex3f( c * rad, s * rad, w2 );
}
glNormal3f( 1.0, 0.0, 0.0 );
glVertex3f( rad, 0.0, w1 );
glVertex3f( rad, 0.0, w2 );
glEnd();
}
}
Profile gear_profile[] =
{
{ 0.000, 0.0 },
{ 0.300, 7.0 },
{ 0.340, 0.4 },
{ 0.550, 0.64 },
{ 0.600, 0.4 },
{ 0.950, 1.0 }
};
float a1 = 27.0;
float a2 = 67.0;
float a3 = 47.0;
float a4 = 87.0;
float i1 = 1.2;
float i2 = 3.1;
float i3 = 2.3;
float i4 = 1.1;
void oneFrame( void )
{
#ifndef __USE_GLUT__
/* Jeûeli uûywamy MiniGL, to konieczne jest zatroszczenie sië o
blokowanie dostëpu do ukîadu 3D. W przypadku OpenGL/StormMESY
jest to robione automatycznie */
mglLockDisplay();
#endif
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
if( show & 1 )
{
glPushMatrix();
glTranslatef( 0.0, 0.0, -4.0 );
glRotatef( a3, 1.0, 1.0, 1.0 );
glRotatef( a4, 0.0, 0.0, -1.0 );
glTranslatef( 0.14, 0.2, 0.0 );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
gear( 40,
0.4, 2.0, 1.1,
0.8, 0.4,
sizeof(gear_profile) / sizeof(Profile), gear_profile);
glPopMatrix();
}
if( show & 2 )
{
glPushMatrix();
glTranslatef( 0.1, 0.2, -3.8 );
glRotatef( a2, -4.0, 2.0, -1.0 );
glRotatef( a1, 1.0, -3.0, 1.0 );
glTranslatef( 0.0, -0.2, 0.0 );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glColor3f( 1.0, 0.8, 0.0 );
gear( 36,
0.4, 2.0, 1.1,
0.7, 0.2,
sizeof(gear_profile) / sizeof(Profile), gear_profile);
glPopMatrix();
}
a1 += i1;
if( a1 > 360.0 )
a1 -= 360.0;
if( a1 < 0.0 )
a1 -= 360.0;
a2 += i2;
if( a2 > 360.0 )
a2 -= 360.0;
if( a2 < 0.0 )
a2 -= 360.0;
a3 += i3;
if( a3 > 360.0 )
a3 -= 360.0;
if( a3 < 0.0 )
a3 -= 360.0;
a4 += i4;
if( a4 > 360.0 )
a4 -= 360.0;
if( a4 < 0.0 )
a4 -= 360.0;
/* Po narysowaniu caîej klatki animacji wyôwietlamy jâ
i w przypadku MiniGL odblokowujemy ukîad 3D */
#ifdef __USE_GLUT__
glutSwapBuffers();
#else
mglUnlockDisplay();
mglSwitchDisplay();
#endif
}
#ifdef __USE_GLUT__
void idle( void )
{
glutPostRedisplay();
}
#endif
void myReshape( int w, int h )
{
glViewport( 0, 0, w, h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -1.0, 1.0, -1.0, 1.0, d_near, d_far );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
void myinit( int w, int h )
{
glClearColor( 0.0, 0.0, 0.0, 0.0 );
myReshape( w, h );
glEnable( GL_DEPTH_TEST );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
/* Funkcja obsîugi klawiatury w MiniGL róûni sië nieco
w stosunku do GLUT, na szczeôcie kody klawiszy sâ takie same */
#ifdef __USE_GLUT__
void keys( unsigned char c, int x, int y )
#else
void keys( char c )
#endif
{
switch( c )
{
case 27: {
/* W przypadku GLUT moûemy zrobiê po prostu 'exit'
- biblioteka sama zatroszczy sië o zamkniëcia okna,
usuniëcie kontekstu itd. W MiniGL uûywamy 'mglExit'
sprzâtamy po sobie (zobacz na koïcu funkcji 'main'). */
#ifdef __USE_GLUT__
exit( 0 );
#else
mglExit();
#endif
};
case '1': show = 1; break;
case '2': show = 2; break;
case '3': show = 3; break;
case 'e': if( bEnvMap == GL_TRUE )
{
bEnvMap = GL_FALSE;
glDisable( GL_TEXTURE_GEN_S );
glDisable( GL_TEXTURE_GEN_T );
}
else
{
bEnvMap = GL_TRUE;
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
};
break;
case 's': {
/* Zapis obrazka do pliku 'screenshot.ppm',
funkcja ta jest dostëpna tylko w MiniGL */
#ifndef __USE_GLUT__
mglWriteShotPPM( "screenshot.ppm" );
#endif
};
break;
}
}
int main( int argc, char *argv[] )
{
GLint width = 640; GLint height = 480;
int i;
char *name = 0;
GLboolean windowmode = GL_FALSE;
for( i = 1 ; i < argc ; i++)
{
if( 0 == stricmp( argv[i], "-width" ) )
{
i++;
width = atoi( argv[i] );
}
else
if( 0 == stricmp( argv[i], "-height" ) )
{
i++;
height = atoi( argv[i] );
}
else
if( 0 == stricmp( argv[i], "-envmap" ) )
{
i++;
name = argv[i];
}
else
if( 0 == stricmp( argv[i], "-window" ) )
{
windowmode = GL_TRUE;
};
};
/* Inicjalizacja biblioteki, utworzenie kontekstu i okna.
To widoczne sâ najistotniejsze róûnice miëdzy MiniGL
a OpenGL/GLUT */
#ifndef __USE_GLUT__
MGLInit();
mglChooseWindowMode( windowmode );
mglChooseVertexBufferSize( 1000 );
mglChooseNumberOfBuffers( 3 );
mglChoosePixelDepth( 16 );
mglCreateContext( 0, 0, width, height );
mglEnableSync( GL_FALSE );
#else
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
if( !windowmode )
glutEnterGameMode();
else
{
glutInitWindowSize( width, height );
glutCreateWindow( "" );
};
#endif
if( TexInit(name) )
{
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glDisable( GL_CULL_FACE );
/* Dostëpne tylko w MiniGL, wymusza uûycie szybszej
procedury mnoûenia wektora przez macierz */
#ifndef __USE_GLUT__
glHint( MGL_W_ONE_HINT, GL_FASTEST );
#endif
myinit( width, height );
/* Definiowanie callback functions i rozpoczëcie gîównej pëtli */
#ifdef __USE_GLUT__
glutDisplayFunc( oneFrame );
glutReshapeFunc( myReshape );
glutIdleFunc( idle );
glutKeyboardFunc( keys );
glutMainLoop();
#else
mglLockMode( MGL_LOCK_MANUAL );
mglIdleFunc( oneFrame );
mglKeyFunc( keys );
mglMainLoop();
#endif
}
else
printf("Can't find texture %s\n", name);
/* Koïcowe porzâdki - konieczne tylko w MiniGL */
#ifndef __USE_GLUT__
mglDeleteContext();
MGLTerm();
#endif
return 0; /* ANSI C requires main to return int. */
}