4726
|
1 /*
|
|
2 * This code was created by Jeff Molofee '99
|
|
3 * (ported to Linux/SDL by Ti Leggett '01)
|
|
4 *
|
|
5 * If you've found this code useful, please let me know.
|
|
6 *
|
|
7 * Visit Jeff at http://nehe.gamedev.net/
|
|
8 *
|
|
9 * or for port-specific comments, questions, bugreports etc.
|
|
10 * email to leggett@eecs.tulane.edu
|
|
11 */
|
|
12
|
|
13 #include <stdio.h>
|
|
14 #include <stdlib.h>
|
|
15 #include <math.h>
|
|
16
|
|
17 #include <signal.h>
|
|
18
|
|
19 #include <android/log.h>
|
|
20
|
|
21
|
|
22 #ifdef ANDROID
|
|
23 #include <GLES/gl.h>
|
|
24 #else
|
|
25 #include <GL/gl.h>
|
|
26 #include <GL/glu.h>
|
|
27 #endif
|
|
28 #include "SDL.h"
|
|
29
|
|
30 /* screen width, height, and bit depth */
|
|
31 #define SCREEN_WIDTH 320
|
|
32 #define SCREEN_HEIGHT 430
|
|
33 #define SCREEN_BPP 16
|
|
34
|
|
35 /* Define our booleans */
|
|
36 #define TRUE 1
|
|
37 #define FALSE 0
|
|
38
|
|
39 /* This is our SDL surface */
|
|
40 SDL_Surface *surface;
|
|
41
|
|
42 int rotation = 0;
|
|
43
|
|
44
|
|
45 /**************************************
|
|
46 gluperspective implementation
|
|
47 **************************************/
|
|
48 void gluPerspective(double fovy, double aspect, double zNear, double zFar){
|
|
49 glMatrixMode(GL_PROJECTION);
|
|
50 glLoadIdentity();
|
|
51 double xmin, xmax, ymin, ymax;
|
|
52 ymax = zNear * tan(fovy * M_PI / 360.0);
|
|
53 ymin = -ymax;
|
|
54 xmin = ymin * aspect;
|
|
55 xmax = ymax * aspect;
|
|
56 glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);
|
|
57 }
|
|
58
|
|
59
|
|
60 /**************************************
|
|
61 glulookat implementation
|
|
62 **************************************/
|
|
63 void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
|
|
64 GLfloat centerx, GLfloat centery, GLfloat centerz,
|
|
65 GLfloat upx, GLfloat upy, GLfloat upz)
|
|
66 {
|
|
67 GLfloat m[16];
|
|
68 GLfloat x[3], y[3], z[3];
|
|
69 GLfloat mag;
|
|
70
|
|
71 /* Make rotation matrix */
|
|
72
|
|
73 /* Z vector */
|
|
74 z[0] = eyex - centerx;
|
|
75 z[1] = eyey - centery;
|
|
76 z[2] = eyez - centerz;
|
|
77 mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
|
|
78 if (mag) { /* mpichler, 19950515 */
|
|
79 z[0] /= mag;
|
|
80 z[1] /= mag;
|
|
81 z[2] /= mag;
|
|
82 }
|
|
83
|
|
84 /* Y vector */
|
|
85 y[0] = upx;
|
|
86 y[1] = upy;
|
|
87 y[2] = upz;
|
|
88
|
|
89 /* X vector = Y cross Z */
|
|
90 x[0] = y[1] * z[2] - y[2] * z[1];
|
|
91 x[1] = -y[0] * z[2] + y[2] * z[0];
|
|
92 x[2] = y[0] * z[1] - y[1] * z[0];
|
|
93
|
|
94 /* Recompute Y = Z cross X */
|
|
95 y[0] = z[1] * x[2] - z[2] * x[1];
|
|
96 y[1] = -z[0] * x[2] + z[2] * x[0];
|
|
97 y[2] = z[0] * x[1] - z[1] * x[0];
|
|
98
|
|
99 /* mpichler, 19950515 */
|
|
100 /* cross product gives area of parallelogram, which is < 1.0 for
|
|
101 * non-perpendicular unit-length vectors; so normalize x, y here
|
|
102 */
|
|
103
|
|
104 mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
|
|
105 if (mag) {
|
|
106 x[0] /= mag;
|
|
107 x[1] /= mag;
|
|
108 x[2] /= mag;
|
|
109 }
|
|
110
|
|
111 mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
|
|
112 if (mag) {
|
|
113 y[0] /= mag;
|
|
114 y[1] /= mag;
|
|
115 y[2] /= mag;
|
|
116 }
|
|
117
|
|
118 #define M(row,col) m[col*4+row]
|
|
119 M(0, 0) = x[0];
|
|
120 M(0, 1) = x[1];
|
|
121 M(0, 2) = x[2];
|
|
122 M(0, 3) = 0.0;
|
|
123 M(1, 0) = y[0];
|
|
124 M(1, 1) = y[1];
|
|
125 M(1, 2) = y[2];
|
|
126 M(1, 3) = 0.0;
|
|
127 M(2, 0) = z[0];
|
|
128 M(2, 1) = z[1];
|
|
129 M(2, 2) = z[2];
|
|
130 M(2, 3) = 0.0;
|
|
131 M(3, 0) = 0.0;
|
|
132 M(3, 1) = 0.0;
|
|
133 M(3, 2) = 0.0;
|
|
134 M(3, 3) = 1.0;
|
|
135 #undef M
|
|
136 glMultMatrixf(m);
|
|
137
|
|
138 /* Translate Eye to Origin */
|
|
139 glTranslatef(-eyex, -eyey, -eyez);
|
|
140
|
|
141 }
|
|
142
|
|
143
|
|
144
|
|
145
|
|
146
|
|
147 /* function to release/destroy our resources and restoring the old desktop */
|
|
148 void Quit( int returnCode )
|
|
149 {
|
|
150 /* clean up the window */
|
|
151 SDL_Quit( );
|
|
152
|
|
153 /* and exit appropriately */
|
|
154 exit( returnCode );
|
|
155 }
|
|
156
|
|
157 /* function to reset our viewport after a window resize */
|
|
158 int resizeWindow( int width, int height )
|
|
159 {
|
|
160 /* Height / width ration */
|
|
161 GLfloat ratio;
|
|
162
|
|
163 /* Protect against a divide by zero */
|
|
164 if ( height == 0 )
|
|
165 height = 1;
|
|
166
|
|
167 ratio = ( GLfloat )width / ( GLfloat )height;
|
|
168
|
|
169 /* Setup our viewport. */
|
|
170 glViewport( 0, 0, ( GLsizei )width, ( GLsizei )height );
|
|
171
|
|
172 /* change to the projection matrix and set our viewing volume. */
|
|
173 glMatrixMode( GL_PROJECTION );
|
|
174 glLoadIdentity( );
|
|
175
|
|
176 /* Set our perspective */
|
|
177 gluPerspective( 45.0f, ratio, 0.1f, 100.0f );
|
|
178
|
|
179 /* Make sure we're chaning the model view and not the projection */
|
|
180 glMatrixMode( GL_MODELVIEW );
|
|
181
|
|
182 /* Reset The View */
|
|
183 glLoadIdentity( );
|
|
184
|
|
185 return( TRUE );
|
|
186 }
|
|
187
|
|
188 /* function to handle key press events */
|
|
189 void handleKeyPress( SDL_keysym *keysym )
|
|
190 {
|
|
191 switch ( keysym->sym )
|
|
192 {
|
|
193 case SDLK_ESCAPE:
|
|
194 /* ESC key was pressed */
|
|
195 Quit( 0 );
|
|
196 break;
|
|
197 case SDLK_F1:
|
|
198 /* F1 key was pressed
|
|
199 * this toggles fullscreen mode
|
|
200 */
|
|
201 SDL_WM_ToggleFullScreen( surface );
|
|
202 break;
|
|
203 case SDLK_LEFT:
|
|
204 rotation -= 30;
|
|
205 break;
|
|
206
|
|
207 case SDLK_RIGHT:
|
|
208 rotation += 30;
|
|
209 break;
|
|
210
|
|
211 default:
|
|
212 break;
|
|
213 }
|
|
214
|
|
215 __android_log_print(ANDROID_LOG_INFO, "SDL","Keycode: %d, %d, %d\n", keysym->sym, SDLK_LEFT, SDLK_RIGHT);
|
|
216
|
|
217 return;
|
|
218 }
|
|
219
|
|
220 /* general OpenGL initialization function */
|
|
221 int initGL( GLvoid )
|
|
222 {
|
|
223
|
|
224 /* Enable smooth shading */
|
|
225 glShadeModel( GL_SMOOTH );
|
|
226
|
|
227 /* Set the background black */
|
|
228 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
|
229
|
|
230 /* Depth buffer setup */
|
|
231 //glClearDepth( 1.0f );
|
|
232
|
|
233 /* Enables Depth Testing */
|
|
234 glEnable( GL_DEPTH_TEST );
|
|
235
|
|
236 /* The Type Of Depth Test To Do */
|
|
237 glDepthFunc( GL_LEQUAL );
|
|
238
|
|
239 /* Really Nice Perspective Calculations */
|
|
240 glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
|
241
|
|
242 return( TRUE );
|
|
243 }
|
|
244
|
|
245 /* Here goes our drawing code */
|
|
246 int drawGLScene( GLvoid )
|
|
247 {
|
|
248
|
|
249 static int Frames = 0;
|
|
250 static int T0 = 0;
|
|
251
|
|
252 glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
253
|
|
254 glClearColorx(0,0,0,255);
|
|
255 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
256
|
|
257 glMatrixMode(GL_PROJECTION);
|
|
258 glLoadIdentity();
|
|
259 gluPerspective(45, (float)SCREEN_WIDTH / SCREEN_HEIGHT, 0.5f, 150);
|
|
260
|
|
261 glMatrixMode(GL_MODELVIEW);
|
|
262
|
|
263 glLoadIdentity();
|
|
264
|
|
265 //Camera
|
|
266 gluLookAt(0,0,5, 0,0,0, 0,1,0);
|
|
267
|
|
268 //Draw a triangle
|
|
269 //glRotatef(iRot, 0, 1, 0);
|
|
270
|
|
271 glRotatef( rotation, 0.0f, 1.0f, 0.0f );
|
|
272
|
|
273
|
|
274 glEnableClientState (GL_VERTEX_ARRAY);
|
|
275 glEnableClientState (GL_COLOR_ARRAY);
|
|
276
|
|
277 /* Rotate The Triangle On The Y axis ( NEW ) */
|
|
278 //glRotatef( Frames % 360, 0.0f, 1.0f, 0.0f );
|
|
279
|
|
280 /* GLES variant of drawing a triangle */
|
|
281 const GLfloat triVertices[][9] = {
|
|
282 { /* Front Triangle */
|
|
283 0.0f, 1.0f, 0.0f, /* Top Of Triangle */
|
|
284 -1.0f, -1.0f, 1.0f, /* Left Of Triangle */
|
|
285 1.0f, -1.0f, 1.0f /* Right Of Triangle */
|
|
286 }, { /* Right Triangle */
|
|
287 0.0f, 1.0f, 0.0f, /* Top Of Triangle */
|
|
288 1.0f, -1.0f, 1.0f, /* Left Of Triangle */
|
|
289 1.0f, -1.0f, -1.0f /* Right Of Triangle */
|
|
290 }, { /* Back Triangle */
|
|
291 0.0f, 1.0f, 0.0f, /* Top Of Triangle */
|
|
292 1.0f, -1.0f, -1.0f, /* Left Of Triangle */
|
|
293 -1.0f, -1.0f, -1.0f /* Right Of Triangle */
|
|
294 }, { /* Left Triangle */
|
|
295 0.0f, 1.0f, 0.0f, /* Top Of Triangle */
|
|
296 -1.0f, -1.0f, -1.0f, /* Left Of Triangle */
|
|
297 -1.0f, -1.0f, 1.0f /* Right Of Triangle */
|
|
298 }
|
|
299 };
|
|
300
|
|
301 /* unlike GL, GLES does not support RGB. We have to use RGBA instead */
|
|
302 const GLfloat triColors[][12] = {
|
|
303 { /* Front triangle */
|
|
304 1.0f, 0.0f, 0.0f, 1.0f, /* Red */
|
|
305 0.0f, 1.0f, 0.0f, 1.0f, /* Green */
|
|
306 0.0f, 0.0f, 1.0f, 1.0f /* Blue */
|
|
307 }, { /* Right triangle */
|
|
308 1.0f, 0.0f, 0.0f, 1.0f, /* Red */
|
|
309 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */
|
|
310 0.0f, 1.0f, 0.0f, 1.0f /* Green */
|
|
311 }, { /* Back triangle */
|
|
312 1.0f, 0.0f, 0.0f, 1.0f, /* Red */
|
|
313 0.0f, 1.0f, 0.0f, 1.0f, /* Green */
|
|
314 0.0f, 0.0f, 1.0f, 1.0f /* Blue */
|
|
315 }, { /* Left triangle */
|
|
316 1.0f, 0.0f, 0.0f, 1.0f, /* Red */
|
|
317 0.0f, 0.0f, 1.0f, 1.0f, /* Blue */
|
|
318 0.0f, 1.0f, 0.0f, 1.0f /* Green */
|
|
319 }
|
|
320 };
|
|
321
|
|
322 glEnableClientState(GL_COLOR_ARRAY);
|
|
323
|
|
324 int tri=0;
|
|
325
|
|
326 /* Loop through all Triangles */
|
|
327 for(tri=0;tri<sizeof(triVertices)/(9*sizeof(GLfloat));tri++)
|
|
328 {
|
|
329 glVertexPointer(3, GL_FLOAT, 0, triVertices[tri]);
|
|
330 glColorPointer(4, GL_FLOAT, 0, triColors[tri]);
|
|
331
|
|
332 glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
|
|
333 }
|
|
334
|
|
335 //__android_log_print(ANDROID_LOG_INFO, "SDL", "render %d", Frames++);
|
|
336
|
|
337 /* Draw it to the screen */
|
|
338 SDL_GL_SwapBuffers( );
|
|
339
|
|
340 /* Gather our frames per second */
|
|
341 Frames++;
|
|
342 {
|
|
343 GLint t = SDL_GetTicks();
|
|
344 if (t - T0 >= 5000) {
|
|
345 GLfloat seconds = (t - T0) / 1000.0;
|
|
346 GLfloat fps = Frames / seconds;
|
|
347 __android_log_print(ANDROID_LOG_INFO, "SDL","%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
|
|
348 T0 = t;
|
|
349 Frames = 0;
|
|
350 }
|
|
351 }
|
|
352
|
|
353 rotation++;
|
|
354
|
|
355 return( TRUE );
|
|
356 }
|
|
357
|
|
358
|
|
359 struct
|
|
360 {
|
|
361 SDL_AudioSpec spec;
|
|
362 Uint8 *sound; /* Pointer to wave data */
|
|
363 Uint32 soundlen; /* Length of wave data */
|
|
364 int soundpos; /* Current play position */
|
|
365 } wave;
|
|
366
|
|
367 void SDLCALL
|
|
368 fillerup(void *unused, Uint8 * stream, int len)
|
|
369 {
|
|
370 __android_log_print(ANDROID_LOG_INFO, "SDL","FILLERUP\n");
|
|
371
|
|
372 Uint8 *waveptr;
|
|
373 int waveleft;
|
|
374
|
|
375 /* Set up the pointers */
|
|
376 waveptr = wave.sound + wave.soundpos;
|
|
377 waveleft = wave.soundlen - wave.soundpos;
|
|
378
|
|
379 /* Go! */
|
|
380 while (waveleft <= len) {
|
|
381 SDL_memcpy(stream, waveptr, waveleft);
|
|
382 stream += waveleft;
|
|
383 len -= waveleft;
|
|
384 waveptr = wave.sound;
|
|
385 waveleft = wave.soundlen;
|
|
386 wave.soundpos = 0;
|
|
387 }
|
|
388 SDL_memcpy(stream, waveptr, len);
|
|
389 wave.soundpos += len;
|
|
390 }
|
|
391
|
|
392 void testAudio(){
|
|
393
|
|
394 const char *file = "/sdcard/sample.wav";
|
|
395
|
|
396 /* Load the SDL library */
|
|
397 if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
|
398 __android_log_print(ANDROID_LOG_INFO, "SDL","Couldn't initialize SDL Audio: %s\n", SDL_GetError());
|
|
399 return;
|
|
400 }else{
|
|
401 __android_log_print(ANDROID_LOG_INFO, "SDL","Init audio ok\n");
|
|
402 }
|
|
403
|
|
404 /* Load the wave file into memory */
|
|
405 if (SDL_LoadWAV(file, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
|
|
406 __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't load %s: %s\n", file, SDL_GetError());
|
|
407 return;
|
|
408 }
|
|
409
|
|
410 wave.spec.callback = fillerup;
|
|
411
|
|
412 __android_log_print(ANDROID_LOG_INFO, "SDL","Loaded: %d\n", wave.soundlen);
|
|
413
|
|
414
|
|
415 /* Initialize fillerup() variables */
|
|
416 if (SDL_OpenAudio(&wave.spec, NULL) < 0) {
|
|
417 __android_log_print(ANDROID_LOG_INFO, "SDL", "Couldn't open audio: %s\n", SDL_GetError());
|
|
418 SDL_FreeWAV(wave.sound);
|
|
419 return;
|
|
420 }
|
|
421
|
|
422 __android_log_print(ANDROID_LOG_INFO, "SDL","Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
|
|
423
|
|
424 /* Let the audio run */
|
|
425 SDL_PauseAudio(0);
|
|
426
|
|
427 __android_log_print(ANDROID_LOG_INFO, "SDL","Playing\n");
|
|
428
|
|
429 while (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING){
|
|
430 //__android_log_print(ANDROID_LOG_INFO, "SDL","Still playing\n");
|
|
431 SDL_Delay(100);
|
|
432 }
|
|
433
|
|
434 __android_log_print(ANDROID_LOG_INFO, "SDL","Closing down\n");
|
|
435
|
|
436 /* Clean up on signal */
|
|
437 SDL_CloseAudio();
|
|
438 SDL_FreeWAV(wave.sound);
|
|
439 }
|
|
440
|
|
441 int SDL_main( int argc, char **argv )
|
|
442 {
|
|
443
|
|
444 __android_log_print(ANDROID_LOG_INFO, "SDL","entry\n");
|
|
445
|
|
446 /* Flags to pass to SDL_SetVideoMode */
|
|
447 int videoFlags;
|
|
448 /* main loop variable */
|
|
449 int done = FALSE;
|
|
450 /* used to collect events */
|
|
451 SDL_Event event;
|
|
452 /* this holds some info about our display */
|
|
453 const SDL_VideoInfo *videoInfo;
|
|
454 /* whether or not the window is active */
|
|
455 int isActive = TRUE;
|
|
456
|
|
457 /* initialize SDL */
|
|
458 if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
|
|
459 {
|
|
460 __android_log_print(ANDROID_LOG_INFO, "SDL", "Video initialization failed: %s\n",
|
|
461 SDL_GetError( ) );
|
|
462 Quit( 1 );
|
|
463 }
|
|
464
|
|
465 /* Fetch the video info */
|
|
466 videoInfo = SDL_GetVideoInfo( );
|
|
467
|
|
468 if ( !videoInfo )
|
|
469 {
|
|
470 __android_log_print(ANDROID_LOG_INFO, "SDL", "Video query failed: %s\n",
|
|
471 SDL_GetError( ) );
|
|
472 Quit( 1 );
|
|
473 }
|
|
474
|
|
475 /* the flags to pass to SDL_SetVideoMode */
|
|
476 videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */
|
|
477 videoFlags |= SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
|
|
478 videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */
|
|
479 videoFlags |= SDL_RESIZABLE; /* Enable window resizing */
|
|
480
|
|
481 /* This checks to see if surfaces can be stored in memory */
|
|
482 if ( videoInfo->hw_available )
|
|
483 videoFlags |= SDL_HWSURFACE;
|
|
484 else
|
|
485 videoFlags |= SDL_SWSURFACE;
|
|
486
|
|
487 /* This checks if hardware blits can be done */
|
|
488 if ( videoInfo->blit_hw )
|
|
489 videoFlags |= SDL_HWACCEL;
|
|
490
|
|
491 /* Sets up OpenGL double buffering */
|
|
492 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
|
493
|
|
494 /* get a SDL surface */
|
|
495 surface = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
|
|
496 videoFlags );
|
|
497
|
|
498 /* Verify there is a surface */
|
|
499 if ( !surface )
|
|
500 {
|
|
501 __android_log_print(ANDROID_LOG_INFO, "SDL", "Video mode set failed: %s\n", SDL_GetError( ) );
|
|
502 Quit( 1 );
|
|
503 }
|
|
504
|
|
505 __android_log_print(ANDROID_LOG_INFO, "SDL","Made a video mode!\n");
|
|
506
|
|
507 /* initialize OpenGL */
|
|
508 initGL( );
|
|
509
|
|
510 /* resize the initial window */
|
|
511 resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
512
|
|
513
|
|
514 //testAudio();
|
|
515
|
|
516
|
|
517 /* wait for events */
|
|
518 while ( !done )
|
|
519 {
|
|
520 /* handle the events in the queue */
|
|
521
|
|
522 while ( SDL_PollEvent( &event ) )
|
|
523 {
|
|
524 switch( event.type )
|
|
525 {
|
|
526 case SDL_ACTIVEEVENT:
|
|
527 /* Something's happend with our focus
|
|
528 * If we lost focus or we are iconified, we
|
|
529 * shouldn't draw the screen
|
|
530 */
|
|
531 if ( event.active.gain == 0 )
|
|
532 isActive = FALSE;
|
|
533 else
|
|
534 isActive = TRUE;
|
|
535 break;
|
|
536 case SDL_VIDEORESIZE:
|
|
537 /* handle resize event */
|
|
538 surface = SDL_SetVideoMode( event.resize.w,
|
|
539 event.resize.h,
|
|
540 16, videoFlags );
|
|
541 if ( !surface )
|
|
542 {
|
|
543 __android_log_print(ANDROID_LOG_INFO, "SDL","Could not get a surface after resize: %s\n", SDL_GetError( ) );
|
|
544 Quit( 1 );
|
|
545 }
|
|
546 resizeWindow( event.resize.w, event.resize.h );
|
|
547 break;
|
|
548 case SDL_KEYDOWN:
|
|
549 /* handle key presses */
|
|
550 handleKeyPress( &event.key.keysym );
|
|
551 break;
|
|
552 case SDL_QUIT:
|
|
553 /* handle quit requests */
|
|
554 done = TRUE;
|
|
555 __android_log_print(ANDROID_LOG_INFO, "SDL","App is shutting down\n");
|
|
556 break;
|
|
557 default:
|
|
558 break;
|
|
559 }
|
|
560 }
|
|
561
|
|
562 /* draw the scene */
|
|
563 if ( isActive )
|
|
564 drawGLScene( );
|
|
565 }
|
|
566
|
|
567 /* clean ourselves up and exit */
|
|
568 Quit( 0 );
|
|
569
|
|
570 /* Should never get here */
|
|
571 return( 0 );
|
|
572 }
|
|
573
|
|
574
|