1: #line 4296 "./lpsrc/flx_sdl.pak"
2:
3: /*
4: * This code was created by Jeff Molofee '99
5: * (ported to Linux/SDL by Ti Leggett '01)
6: *
7: * If you've found this code useful, please let me know.
8: *
9: * Visit Jeff at http:
10: *
11: * or for port-specific comments, questions, bugreports etc.
12: * email to leggett@eecs.tulane.edu
13: */
14:
15:
16: include "SDL/SDL";
17: include "SDL/SDL_keyboard";
18: include "SDL/SDL_keysym";
19: include "SDL/SDL_video";
20: include "SDL/SDL_events";
21: include "SDL/SDL_timer";
22: include "SDL/SDL_mutex";
23: include "SDL/SDL_opengl";
24:
25: include "flx_faio";
26: include "flx_faio_sdl";
27:
28: open C_hack;
29: open Carray;
30: open MixedInt;
31: open Uint32;
32: open Uint8;
33: open Float;
34:
35: open SDL_h;
36: open SDL_video_h;
37: open SDL_keyboard_h;
38: open SDL_events_h;
39: open SDL_keysym_h;
40: open SDL_timer_h;
41: open SDL_mutex_h;
42:
43:
44: open SDL_events;
45:
46: open SDL_opengl_h;
47:
48: /* screen width, height, and bit depth */
49: val SCREEN_WIDTH = 640;
50: val SCREEN_HEIGHT = 480;
51: val SCREEN_BPP = 16;
52:
53: /* function to reset our viewport after a window resize */
54: proc resizeWindow( wwidth : int, hheight :int)
55: {
56: var height = hheight;
57: var width = wwidth;
58:
59: /* Protect against a divide by zero */
60: if height == 0 do height = 1; done;
61: var ratio = double_of width / double_of height;
62:
63: block_sdl_events event_lock;
64: /* Setup our viewport. */
65: glViewport( 0, 0, width, height );
66:
67: /* change to the projection matrix and set our viewing volume. */
68: glMatrixMode( GL_PROJECTION );
69: glLoadIdentity( );
70:
71: /* Set our perspective */
72: gluPerspective( 45.0, ratio, 0.1, 100.0 );
73:
74: /* Make sure we're chaning the model view and not the projection */
75: glMatrixMode( GL_MODELVIEW );
76:
77: /* Reset The View */
78: glLoadIdentity( );
79: unblock_sdl_events event_lock;
80: }
81:
82: /* function to load in bitmap as a GL texture */
83: proc LoadGLTextures( )
84: {
85: /* Create storage space for the texture */
86: var TextureImage = SDL_LoadBMP(enconst c"media/textures/sdl208.bmp");
87: if isNULL TextureImage do
88: print "Can't load texture file media/textures/sdl208.bmp";
89: Quit 1;
90: done;
91:
92: /* Create The Texture */
93: glGenTextures( 3, texture );
94:
95: /* Typical Texture Generation Using Data From The Bitmap */
96: glBindTexture( GL_TEXTURE_2D, texture.[0] );
97:
98: /* Generate The Texture */
99: glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage.->w,
100: TextureImage.->h, 0, GL_RGB,
101: GL_UNSIGNED_BYTE, TextureImage.->pixels
102: );
103:
104: /* Linear Filtering */
105: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
106: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
107:
108: glBindTexture( GL_TEXTURE_2D, texture.[1] );
109:
110: /* Linear Filtering */
111: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
112: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
113:
114: /* Generate The Texture */
115: glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage.->w,
116: TextureImage.->h, 0, cast[uint] GL_RGB,
117: GL_UNSIGNED_BYTE, TextureImage.->pixels
118: );
119:
120: glBindTexture( GL_TEXTURE_2D, texture.[2] );
121:
122: /* Linear Filtering */
123: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
124: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST );
125:
126: /* Generate The MipMapped Texture ( NEW ) */
127: ignore(gluBuild2DMipmaps(
128: GL_TEXTURE_2D, 3,
129: TextureImage.->w, TextureImage.->h,
130: GL_RGB, GL_UNSIGNED_BYTE,
131: cast[caddress] TextureImage.->pixels
132: ));
133:
134: /* Free up any memory we may have used */
135: SDL_FreeSurface( TextureImage );
136: }
137:
138: /* general OpenGL initialization function */
139: proc initGL()
140: {
141: /* Enable Texture Mapping ( NEW ) */
142: glEnable( GL_TEXTURE_2D );
143:
144: /* Enable smooth shading */
145: glShadeModel( GL_SMOOTH );
146:
147: /* Set the background black */
148: glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
149:
150: /* Depth buffer setup */
151: glClearDepth( 1.0 );
152:
153: /* Enables Depth Testing */
154: glEnable( GL_DEPTH_TEST );
155:
156: /* The Type Of Depth Test To Do */
157: glDepthFunc( GL_LEQUAL );
158:
159: /* Really Nice Perspective Calculations */
160: glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
161:
162: /* Setup The Ambient Light */
163: glLightfv( GL_LIGHT1, GL_AMBIENT, enconst (carray LightAmbient) );
164:
165: /* Setup The Diffuse Light */
166: glLightfv( GL_LIGHT1, GL_DIFFUSE, enconst (carray LightDiffuse) );
167:
168: /* Position The Light */
169: glLightfv( GL_LIGHT1, GL_POSITION, enconst (carray LightPosition) );
170:
171: /* Enable Light One */
172: glEnable( GL_LIGHT1 );
173:
174: /* Full Brightness, 50% Alpha ( NEW ) */
175: glColor4f( 1.0f, 1.0f, 1.0f, 0.5f);
176:
177: /* Blending Function For Translucency Based On Source Alpha Value */
178: glBlendFunc( GL_SRC_ALPHA, GL_ONE );
179: }
180:
181: /* These are to calculate our fps */
182: var T0 = 0;
183: var Frames = 0;
184:
185: var xrot = 0.0f; /* X Rotation ( NEW ) */
186: var yrot = 0.0f; /* Y Rotation ( NEW ) */
187: var z = -5.0f; /* Depth Into The Screen */
188:
189: var xspeed = 0.0f;
190: var yspeed = 0.0f;
191:
192: proc rotate()
193: {
194: xrot += xspeed; /* Add xspeed To xrot */
195: yrot += yspeed; /* Add yspeed To yrot */
196: }
197:
198:
199: var light = false; /* Whether or not lighting is on */
200: var blend = false; /* Whether or not blending is on */
201:
202:
203: /* Ambient Light Values ( NEW ) */
204: var LightAmbient = 0.5f, 0.5f, 0.5f, 1.0f;
205:
206: /* Diffuse Light Values ( NEW ) */
207: var LightDiffuse = 1.0f, 1.0f, 1.0f, 1.0f;
208:
209: /* Light Position ( NEW ) */
210: var LightPosition = 0.0f, 0.0f, 2.0f, 1.0f;
211:
212: var filter = 0;
213:
214: var f_texture : uint ^ 3; /* Storage For 3 Textures ( NEW ) */
215: var texture : carray[uint] = carray f_texture;
216:
217:
218: /* Here goes our drawing code */
219: proc drawGLScene(drawing:1->0)
220: {
221: block_sdl_events event_lock;
222: drawing();
223: unblock_sdl_events event_lock;
224:
225: /* Gather our frames per second */
226: Frames++;
227: {
228: var t = SDL_GetTicks();
229: if t - T0 >= 5000 do
230: val seconds = double_of (t - T0) / 1000.0;
231: val fps = double_of Frames / seconds;
232: print Frames; print " frames in "; print seconds;
233: print " seconds = "; print fps; print " FPS"; endl;
234: T0 = t;
235: Frames = 0;
236: done;
237: };
238: rotate();
239: }
240:
241: /* whether or not the window is active */
242: var isActive = true;
243:
244: if SDL_Init(SDL_INIT_AUDIO \| SDL_INIT_VIDEO) < 0 do
245: print "Unable to init SDL"; endl;
246: System::exit(1);
247: done;
248:
249: var event_lock = SDL_CreateMutex();
250:
251:
252: proc Quit(n:int)
253: {
254: SDL_Quit;
255: System::exit 0;
256: }
257:
258: /* Fetch the video info */
259: var videoInfo = SDL_GetVideoInfo();
260:
261: if isNULL videoInfo do
262: print "Video query failed"; endl;
263: Quit 1;
264: done;
265:
266: /* the flags to pass to SDL_SetVideoMode */
267: var
268: videoFlags = SDL_OPENGL; /* Enable OpenGL in SDL */
269: videoFlags |= cast[uint] SDL_GL_DOUBLEBUFFER; /* Enable double buffering */
270: videoFlags |= SDL_HWPALETTE; /* Store the palette in hardware */
271: videoFlags |= SDL_RESIZABLE; /* Enable window resizing */
272:
273: /* This checks to see if surfaces can be stored in memory */
274: if videoInfo.->hw_available != 0 do
275: videoFlags |= SDL_HWSURFACE;
276: else
277: videoFlags |= SDL_SWSURFACE;
278: done;
279:
280: /* This checks if hardware blits can be done */
281: if videoInfo.->blit_hw != 0 do
282: videoFlags |= SDL_HWACCEL;
283: done;
284:
285: /* Sets up OpenGL double buffering */
286: ignore$ SDL_GL_SetAttribute( cast[SDL_GLattr] SDL_GL_DOUBLEBUFFER, 1 );
287:
288: /* get a SDL surface */
289: var surface = SDL_SetVideoMode
290: (SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, videoFlags )
291: ;
292:
293: /* Verify there is a surface */
294: if isNULL surface do
295: print "Video mode set failed"; endl;
296: Quit 1;
297: done;
298:
299: /* initialize OpenGL */
300: initGL();
301: LoadGLTextures();
302:
303: /* resize the initial window */
304: resizeWindow( SCREEN_WIDTH, SCREEN_HEIGHT );
305:
306:
307: proc handle_active (e:SDL_ActiveEvent)
308: {
309: isActive = e.gain != 0;
310: }
311:
312: proc handle_resize(e:SDL_ResizeEvent)
313: {
314: block_sdl_events event_lock;
315: surface = SDL_SetVideoMode(
316: e.w,
317: e.h,
318: 16, videoFlags
319: );
320: if isNULL surface do
321: print "Could not get a surface after resize"; endl;
322: done;
323: resizeWindow( e.w, e.h );
324: unblock_sdl_events event_lock;
325: }
326:
327: /* function to handle key press events */
328: proc handle_key( keysym : SDL_keysym)
329: {
330: match keysym.sym with
331: | ?k when k == SDLK_ESCAPE => { Quit 0; }
332: | ?k when k == SDLK_F1 =>
333: { ignore$ SDL_WM_ToggleFullScreen( surface ); }
334: | ?k when k == SDLK_b =>
335: {
336: blend = not blend;
337: if blend do
338: glEnable( GL_BLEND );
339: glDisable( GL_DEPTH_TEST );
340: else
341: glDisable( GL_BLEND );
342: glEnable( GL_DEPTH_TEST );
343: done;
344: }
345: | ?k when k == SDLK_f =>
346: {
347: filter = ( filter + 1) % 3;
348: print "Filter "; print filter; endl;
349: }
350: | ?k when k == SDLK_l =>
351: {
352: light = not light;
353: if not light do
354: glDisable( GL_LIGHTING );
355: else
356: glEnable( GL_LIGHTING );
357: done;
358: }
359: | ?k when k == SDLK_PAGEUP =>
360: {
361: z = z - 0.02f;
362: }
363:
364: | ?k when k == SDLK_PAGEDOWN =>
365: {
366: z = z + 0.02f;
367: }
368:
369: | ?k when k == SDLK_UP =>
370: {
371: xspeed = xspeed - 0.01f;
372: }
373:
374: | ?k when k == SDLK_DOWN =>
375: {
376: xspeed = xspeed + 0.01f;
377: }
378:
379: | ?k when k == SDLK_RIGHT =>
380: {
381: yspeed = yspeed + 0.01f;
382: }
383:
384: | ?k when k == SDLK_LEFT =>
385: {
386: yspeed = yspeed - 0.01f;
387: }
388:
389: | _ => {}
390: endmatch;
391: }
392:
393: /* draw the scene */
394: proc draw(drawing: 1->0) {
395: if isActive call drawGLScene( drawing );
396: }
397:
398: proc keychan(x:schannel[SDL_keysym])
399: {
400: whilst true do
401: var &k : SDL_keysym <- read x;
402: handle_key k;
403: done;
404: }
405:
406: proc activechan(x:schannel[SDL_ActiveEvent])
407: {
408: whilst true do
409: var &k : SDL_ActiveEvent <- read x;
410: handle_active k;
411: done;
412: }
413:
414: proc resizechan(x:schannel[SDL_ResizeEvent])
415: {
416: whilst true do
417: var &k : SDL_ResizeEvent <- read x;
418: handle_resize k;
419: done;
420: }
421:
422: proc drawchan(x:schannel[int], drawing:1->0)
423: {
424: whilst true do
425: var &k : int <- read x;
426: draw drawing;
427: done;
428: }
429:
430: proc execute(x:schannel[int], something:1->0)
431: {
432: whilst true do
433: var &k : int <- read x;
434: something();
435: done;
436: }
437:
438: val clock = Faio::mk_alarm_clock();
439: proc poll_event(e: &SDL_Event)
440: {
441: tryagain:>
442:
443: var result = SDL_PollEvent(unref e);
444: if result > 0 do
445:
446: return;
447: done;
448: Faio::sleep$ clock, 0.1;
449: goto tryagain;
450: }
451:
452: proc dispatch_event(
453: keyboard:schannel[SDL_keysym],
454: active:schannel[SDL_ActiveEvent],
455: resize:schannel[SDL_ResizeEvent]
456: )
457: {
458: whilst true do
459:
460: var e : SDL_Event;
461: poll_event(&e);
462: match e.type_ with
463: | ?et when et == SDL_ACTIVEEVENT =>
464: { write (active, e.active); }
465:
466: | ?et when et == SDL_VIDEORESIZE =>
467: { write (resize, e.resize); }
468:
469: | ?et when et == SDL_KEYDOWN =>
470: { write (keyboard, e.key.keysym); }
471:
472: | ?et when et == SDL_QUIT =>
473: { Quit 0; }
474:
475: | _ => {}
476: endmatch;
477: done;
478: }
479:
480: /* write ticks at the desired framerate */
481: proc framerate (x:schannel[int], framerate:double)
482: {
483: whilst true do
484: Faio::sleep$ clock, framerate;
485: write (x,1);
486: done;
487: }
488:
489: /* LINEAR CONTROL MODEL: CANNOT DEADLOCK
490: ~~> async/sync connection
491: --> sync/sync connection
492:
493: SDL_event ~~> dispatcher
494: --> resize handler
495: --> active handler
496: --> key handler
497: timer ~~> framerate --> draw
498: */
499:
500: /* make our communication channels */
501: var keyboard = mk_schannel[SDL_keysym] ();
502: var active = mk_schannel[SDL_ActiveEvent] ();
503: var resize = mk_schannel[SDL_ResizeEvent] ();
504: var clicks = mk_schannel[int] ();
505: var rotation = mk_schannel[int] ();
506:
507: /* start up the fthreads and plug them together */
508: spawn_fthread { dispatch_event (keyboard, active, resize); };
509: spawn_fthread { resizechan resize; };
510: spawn_fthread { activechan active; };
511: spawn_fthread { keychan keyboard; };
512:
513: spawn_fthread { drawchan (clicks, the Drawing); };
514: spawn_fthread { framerate (clicks, 0.05); };
515: spawn_fthread { execute (rotation, the rotate); };
516: spawn_fthread { framerate (rotation, 0.01); };
517:
518:
519:
520:
521: /* Here goes our drawing code */
522: proc Drawing()
523: {
524: /* Clear The Screen And The Depth Buffer */
525: glClear( GL_COLOR_BUFFER_BIT \| GL_DEPTH_BUFFER_BIT );
526:
527: /* Reset the view */
528: glLoadIdentity( );
529:
530: /* Translate Into/Out Of The Screen By z */
531: glTranslatef( 0.0f, 0.0f, z );
532:
533: glRotatef( xrot, 1.0f, 0.0f, 0.0f); /* Rotate On The X Axis By xrot */
534: glRotatef( yrot, 0.0f, 1.0f, 0.0f); /* Rotate On The Y Axis By yrot */
535:
536: /* Select A Texture Based On filter */
537: glBindTexture( GL_TEXTURE_2D, texture.[filter] );
538:
539: /* Start Drawing Quads */
540: glBegin( GL_QUADS );
541: /* Front Face */
542: /* Normal Pointing Towards Viewer */
543: glNormal3f( 0.0f, 0.0f, 1.0f );
544: /* Point 1 (Front) */
545: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
546: /* Point 2 (Front) */
547: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
548: /* Point 3 (Front) */
549: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
550: /* Point 4 (Front) */
551: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
552:
553: /* Back Face */
554: /* Normal Pointing Away From Viewer */
555: glNormal3f( 0.0f, 0.0f, -1.0f);
556: /* Point 1 (Back) */
557: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
558: /* Point 2 (Back) */
559: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
560: /* Point 3 (Back) */
561: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
562: /* Point 4 (Back) */
563: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
564:
565: /* Top Face */
566: /* Normal Pointing Up */
567: glNormal3f( 0.0f, 1.0f, 0.0f );
568: /* Point 1 (Top) */
569: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
570: /* Point 2 (Top) */
571: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
572: /* Point 3 (Top) */
573: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
574: /* Point 4 (Top) */
575: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
576:
577: /* Bottom Face */
578: /* Normal Pointing Down */
579: glNormal3f( 0.0f, -1.0f, 0.0f );
580: /* Point 1 (Bottom) */
581: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
582: /* Point 2 (Bottom) */
583: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
584: /* Point 3 (Bottom) */
585: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
586: /* Point 4 (Bottom) */
587: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
588:
589: /* Right face */
590: /* Normal Pointing Right */
591: glNormal3f( 1.0f, 0.0f, 0.0f);
592: /* Point 1 (Right) */
593: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, -1.0f );
594: /* Point 2 (Right) */
595: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, -1.0f );
596: /* Point 3 (Right) */
597: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( 1.0f, 1.0f, 1.0f );
598: /* Point 4 (Right) */
599: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( 1.0f, -1.0f, 1.0f );
600:
601: /* Left Face*/
602: /* Normal Pointing Left */
603: glNormal3f( -1.0f, 0.0f, 0.0f );
604: /* Point 1 (Left) */
605: glTexCoord2f( 1.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, -1.0f );
606: /* Point 2 (Left) */
607: glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -1.0f, -1.0f, 1.0f );
608: /* Point 3 (Left) */
609: glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, 1.0f );
610: /* Point 4 (Left) */
611: glTexCoord2f( 1.0f, 1.0f ); glVertex3f( -1.0f, 1.0f, -1.0f );
612: glEnd();
613:
614: /* Draw it to the screen */
615: SDL_GL_SwapBuffers( );
616:
617: }